Java源码学习笔记之lang包——包装类String.class

前言:为学习所发现而记录。

           JDK 版本:1.8

按照惯例,还是先把方法全去掉瞅瞅有什么接口,有什么属性再说。

 
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {    
    private final char value[];
    private int hash; // Default to 0
    public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                         = new CaseInsensitiveComparator();
    private static class CaseInsensitiveComparator
            implements Comparator<String>, java.io.Serializable {
    }
}

前两个接口咱们很熟了,一个序列化的接口,一个同类型比较的接口,最后一个还没见过。

下面内容转载自 https://blog.csdn.net/qin_jian_bo/article/details/25649519

方法: charAt(int index),返回指定索引处的字符

toString(),   返回一个包含此序列中字符的字符串,该字符串与此序列的顺序相同。字符串的长度就是此序列的长度。

length(),  返回该字符序列的长度

subSequence(),  返回一个新的charsequence子序列

CharSequence 接口,是一个字符 char 序列,也就是为了这三个基于char序列的各种类型做个集合接口。

看着这个图我又有了新问题,到底什么时候用继承,什么时候用接口呢? 在此我做了相关思考 https://mp.csdn.net/postedit/81084215

现在我们再看String的域

最最重要的当然就是 private final char value[];一个String的内部其实还是用 char 实现的.(char在java中是2个字节。java采用unicode,2个字节(16位)来表示一个字符。(默认状态))

其内部的操作也都是基于char[]去操作的,这就解答了一个以前我想到问题,String是谁的包装类呢?int的包装类是Integer,char的包装类是Character,String其实就是char[]的包装类。

咦,String还有个内部类,这个内部类也很奇妙。

    private static class CaseInsensitiveComparator
            implements Comparator<String>, java.io.Serializable {
        // use serialVersionUID from JDK 1.2.2 for interoperability
        private static final long serialVersionUID = 8575799808933029326L;

        public int compare(String s1, String s2) {
            int n1 = s1.length();
            int n2 = s2.length();
            int min = Math.min(n1, n2);
            for (int i = 0; i < min; i++) {
                char c1 = s1.charAt(i);
                char c2 = s2.charAt(i);
                if (c1 != c2) {
                    c1 = Character.toUpperCase(c1);
                    c2 = Character.toUpperCase(c2);
                    if (c1 != c2) {
                        c1 = Character.toLowerCase(c1);
                        c2 = Character.toLowerCase(c2);
                        if (c1 != c2) {
                            // No overflow because of numeric promotion
                            return c1 - c2;
                        }
                    }
                }
            }
            return n1 - n2;
        }

它实现了Comarator<String>接口。

    public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

这俩大同小异,简略来讲内部类中的实现就是忽略大小写。,但是这里有两个奇怪的地方。

第一:为什么要转化为大写比较一次,又转换为小写再比较一次?

         解答:(regionMatches方法中)sun自己都说了 // Unfortunately, conversion to uppercase does not work properly

if (ignoreCase) {
                // If characters don't match but case may be ignored,
                // try converting both characters to uppercase.
                // If the results match, then the comparison scan should
                // continue.
                char u1 = Character.toUpperCase(c1);
                char u2 = Character.toUpperCase(c2);
                if (u1 == u2) {
                    continue;
                }
                // Unfortunately, conversion to uppercase does not work properly
                // for the Georgian alphabet, which has strange rules about case
                // conversion.  So we need to make one last check before
                // exiting.
                if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
                    continue;
                }
            }

我们上面也说了java中的char装的可是unicode,是全世界语言的一个子集,这里面不幸的包括了  像Georgian语言,这种有牛鬼蛇神字母。sun公司也没办法。(我猜测这个字母没有大小写的概念,或者特别混乱)。奇怪的BUG,总有奇怪的解决办法。

第二:Comparator<String>和Comparable<String>这俩很像,那么有什么区别呢?

以至于  https://www.cnblogs.com/listenfwind/p/8450241.html  @且聆听风 这位仁兄,好像没看出来。(PS:也误导了我半个小时)

解答:看名字其实也能略知一二,这俩都是排序的接口,Comparable<>就是可排序的,是为自己排序。Comparator<String>

比较器,就是帮别人排序的。(PS:有的时候看代码还得仔细啊,乌龙就搞笑了。另外疑惑了使用编译器,也可以很快的帮你找到错误,一个编译错误就看出来

按照思考逻辑上,前面两个包装类(Boolean 和 Integer.) 都是有自己的缓存机制的,那么String有吗?

       还真有!只不过这一段是在JVM实现的,并且这一段的功能还可能是靠JNI。(从String.intern()猜测)。暂时没找到实现代码,所以从结果得出答案。

代码:

结果:

 

总结:在编译期可知的对象引用情况下,就可以存入字符串池,这跟局部变量表的规则一样。啥叫编译期可知呢?作为一个引用最关心就是对象的地址,new 的操作就是在堆上申请。也就是说暂时不知道具体地址。“a”形似与这样就是像组成原理里面的立即数的概念,马上知道了地址。

猜你喜欢

转载自blog.csdn.net/qq_36144187/article/details/81067289