String类型
string类型底层实为char[ ]的数组,且为final修饰,故String是不可变的
原因:数组不可扩容,final是不可变量
equals()方法为什么比较的是值?
通过翻阅String类型的源码
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
不难发现,实际是通过循环判断数组同位置的值是否相等,若两数组同位置同值均相等,则表示这两个字符串的值是相等的
hashcode()方法
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
//此处因为在String中value为char类型的数组,
//故31 * h + val[i];实际为int类型整数
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
疑问:为什么乘以31?
在名著 《Effective Java》第 42 页就有对 hashCode 为什么采用 31 做了说明。之所以使用 31, 是因为他是一个奇素数。如果乘数是偶数,并且乘法溢出的话,信息就会丢失,因为与2相乘等价于移位运算(低位补0)。使用素数的好处并不很明显,但是习惯上使用素数来计算散列结果。 31 有个很好的性能,即用移位和减法来代替乘法,可以得到更好的性能: 31 * i == (i << 5)- i, 现代的 VM 可以自动完成这种优化。这个公式可以很简单的推导出来。
replaceAll()与replace()的区别
replaceAll( )为按正则表达式替换
replace( )为数组模式替换
String 和 new String()的区别
For Example
String str1 = “ABC”
String str2 = new String(“ABC”);
String str1 = “ABC”; 可能创建一个对象或者不创建对象。
如果"ABC" 这个字符串z在java String池中不存在,会在java String池中创建一个String str1= "ABC"的对象。然后把str1指向这个内存地址。之后用这种方式创建多少个值为"ABC"的字符串对象。始终只有一个内存地址被分配,之后都是String的copy。这种被称为‘字符串驻留’,所有的字符串都会在编译之后自动驻留。
String str2 = new String(“ABC”); 至少会创建一个对象,也可能2个。
因为用到了new的关键字,肯定会在heap中创建一个str2的对象。它的value值是"ABC",同时如果这个字符串在string池中不存在,会在string词中创建这个string对象"ABC"。
String str1 = new String("ABC");
String str2 = new String("ABC");
System.out.println(str1.equals(str2)); // true 比较的值
System.out.println(str1 == str2); // false 比较的是内存地址。
String str3 = "ABC"
String str4 = "ABC"
String str5 = "AB"+"C";
System.out.println(str3 == str4); //true 在string池中都是一个内存地址被分配给str3,str4,str5
System.out.println(str3 == str5); //true
String str6 = "AB";
String str7 = str6 + "C";
System.out.println(str3 == str7); //false
str6在编译的时候已经确认为string池的对象。
str7在编译的时候不能确认,故str7是一个引用变量。
str6+"C"的过程是创建了一个StringBuffer对象,然后用StringBuffer对象执行append方法追加,最后再转成String类型,也就是str7是放在heap里面的对象,str6是放在String常量池里的。两个的内存地址不一样。故结果为false。