前言:为学习所发现而记录。
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”形似与这样就是像组成原理里面的立即数的概念,马上知道了地址。