String s1 = new String("a") + new String("b");
String s3 = "ab";
s1.intern();
System.out.println(s3==s1);//false
String s1 = new String("a") + new String("b");
s1.intern();
String s3 = "ab";
System.out.println(s3==s1);//true
仅仅因为intern的位置不同,就返回了不同的结果,为什么呢?请问
字符串拼接,会先去常量池中寻找有没有相同的值,
第一段代码:创建s1时,会去常量池找ab这个值,常量池没有,所以新建,创建s3也是如此,新建s3的值,所以两个String对象不同,为false
第二段代码:创建s1时,会去常量池找ab这个值,常量池没有,所以新建,此时执行intern方法,将会把“ab”放到常量池,在新建s3时,先去常量池找有没有,这时候是有“ab”值的,所以s3的引用直接指向常量池的“ab”,此时s1也是指向这个“ab”,所以结果为true
看这里:https://blog.csdn.net/tyyking/article/details/82496901
上测试样例代码:
public class Test {
public static void main(String argv[])
{
String s1 = "HelloWorld";
String s2 = new String("HelloWorld");
String s3 = "Hello";
String s4 = "World";
String s5 = "Hello" + "World";
String s6 = s3 + s4;
System.out.println(s1 == s2);
System.out.println(s1 == s5);
System.out.println(s1 == s6);
System.out.println(s1 == s6.intern());
System.out.println(s2 == s2.intern());
}
}
测试结果:
false
true
false
true
false
解释一下:s1 创建的 HelloWorld 存在于方法区中的常量池其中的字符串池,而 s2 创建的 HelloWorld 存在于堆中,故第一条 false 。
s5 的创建是先进行右边表达式的字符串连接,然后才对 s5 进行赋值。赋值的时候会搜索池中是否有 HelloWorld 字符串,若有则把 s5 引用指向该字符串,若没有则在池中新增该字符串。显然 s5 的创建是用了 s1 已经创建好的字面量,故 true 。
第三个比较容易弄错,s6 = s3 + s4; 其实相当于 s6 = new String(s3 + s4); s6 是存放于堆中的,不是字面量。所以 s1 不等于 s6 。
第四个 s6.intern() 首先获取了 s6 的 HelloWorld 字符串,然后在字符串池中查找该字符串,找到了 s1 的 HelloWorld 并返回。这里如果事前字符串池中没有 HelloWorld 字符串,那么还是会在字符串池中创建一个 HelloWorld 字符串再返回。总之返回的不是堆中的 s6 那个字符串。
第四条也能解释为什么第五条是 false 。s2是堆中的 HelloWorld,s2.intern() 是字符串池中的 HelloWorld 。
关键知识点java 字符串常量池
。intern()
获取的是字符串常量池中的地址。
两块代码的区别只在于第一块代码中只调用了intern()方法,并没有给s1赋值。而第二块代码中将intern()的值赋给了s1
当调用 intern() 方法时,编译器会将字符串添加到常量池中,并返回指向该常量的引用。
图2先调用了intern() ,放入了常量池,s1和s3都是从常量池获取的。
图1,后调用intern() ,s1从常量池获取的,s3并没有,所以返回false