目录
1.问题表述
写这篇文章是我在刷题的时候遇到了这么一道题:
public class TestDemo {
public static void main(String[] args) {
//代码1
String z1 = "zhangsan";
String z2 = new String("zhangsan");
System.out.println("代码1:"+ (z1 == z2));
//代码2
String z3 = new String("lisi");
System.out.println("代码2:" + (z3.intern() == z3));
//代码3
String s1 = new StringBuilder("wangwu").toString();
System.out.println("代码3:" + (s1.intern() == s1));
//代码4
String s2 = new StringBuilder("ma").append("liu").toString();
String intern = s2.intern();
System.out.println("代码4:"+ (intern == s2));
}
}
我们看这个代码,它的打印结果是:
这里我就有一个疑问:为什么代码4是true。
2.问题所需知识讲解
3.问题探究
我们继续来看上面的代码,我是jdk1.8的环境,代码1. z1直接赋值会在常量池中创建zhangsan,但是new String会在堆中创建zhangsan,所以他们的引用地址不一样,所以==比较为false;
代码2. new String("lisi") 会在堆中创建对象,也会在常量池中创建lisi,所以intern拿到常量池中对象进行==比较也会是false。
那么问题来了,代码3和代码4结果为什么不一样呢,他们都是通过StringBuilder创建的对象,
我看了StringBuilder的源码,将他们拆分成了源码级别的代码
package synchronizedTest;
public class TestDemo2 {
public static void main(String[] args) {
//代码1:
String z1 = "zhangsan";
int count = 0;
char[] test = new char[16];
z1.getChars(0,z1.length(),test,count);
count += z1.length();
String s1 = new String(test,0, count);
String s2 = s1.intern();
System.out.println(s2 == s1);
//代码2
String str = "li";
int count1 = 0;
char[] test1 = new char[16];
str.getChars(0,str.length(),test1,count1);
count1 += str.length();
String str1 = "si";
str1.getChars(0,str1.length(),test1, count1);
count1+=str1.length();
String s3 = new String(test1, 0, count1);
String s4 = s3.intern();
System.out.println(s3 == s4);
}
}
我们看他们的结果确实不一样:
4.问题分析
看了源码以后,我猜想new String(value,offset,count) 这个方法只会在堆中创建对象,不会在常量池中创建对象,如果是这样的话就可以解释清楚了
代码3:我在执行:
String s1 = new StringBuilder("wangwu").toString();
的时候,相当于执行:
String test = "wangwu";
String s1 = new StringBuilder(test).toString();
所以会先在常量池中创建wangwu这个对象
然后执行toString()方法,底层执行new String(value,offset,count)这个方法在堆中创建wangwu这个对象
所以调用intern()方法 == 比较为 false
代码4:
和在代码3一样,也会现在常量池中创建“ma”"liu"这两个对象,但是不会创建“maliu”这个对象,然后toString()方法会在堆中创建“maliu”这个对象,调用inter()方法会将堆中"maliu"这个对象的引用地址指向常量池中,所以==比较为true
为了验证我的猜想,我改造一下代码3:我用“zhangsan”这个字符串生成char[]数组,然后生成字符串的时候故意使用5个长度,这样就生成了“zhang”这个字符串,然后调用intern()方法进行比较,果然就变成了true; 验证成功,完美!!!!!
package synchronizedTest;
public class TestDemo2 {
public static void main(String[] args) {
//代码1:
String z1 = "zhangsan";
int count = 0;
char[] test = new char[16];
z1.getChars(0,z1.length(),test,count);
// count += z1.length();
count = 5;
String s1 = new String(test,0, count);
String s2 = s1.intern();
System.out.println(s2 == s1);
//代码2
// String str = "li";
// int count1 = 0;
// char[] test1 = new char[16];
// str.getChars(0,str.length(),test1,count1);
// count1 += str.length();
// String str1 = "si";
// str1.getChars(0,str1.length(),test1, count1);
// count1+=str1.length();
// String s3 = new String(test1, 0, count1);
// String s4 = s3.intern();
// System.out.println(s3 == s4);
}
}
执行结果:
以上观点仅限于个人想法,如果有误请大佬们指正!