以下代码,控制台打印的结果是什么?
public class TestDemo {
@Test
public void test01() {
String str1 = new StringBuilder("hello").append("World").toString();
System.out.println(str1.intern());
System.out.println(str1 == str1.intern());
String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern());
System.out.println(str2 == str2.intern());
String str3 = new StringBuilder("ab").append("c").toString();
System.out.println(str3.intern());
System.out.println(str3 == str3.intern());
String str4 = new StringBuilder("abc").toString();
System.out.println(str4.intern());
System.out.println(str4 == str4.intern());
}
}
控制台打印的结果
helloWorld
true
java
false
abc
true
abc
false
分析
String.intern()
是一个Native方法,它的作用是:如果字符常量池中已经包含一个等于此String对象的字符串,则返回常量池中字符串的引用,否则,将新的字符串放入常量池,并返回新字符串的引用。
intern()有两个作用,第一个是将字符串字面量放入常量池(如果池没有的话),第二个是返回这个常量的引用
- 采用new 创建的字符串对象不进入字符串池;
- 字符串相加的时候,都是静态字符串的结果会添加到字符串池,如果其中含有变量则不会进入字符串池中。
- 第一个:"helloWorld"字符串new出来之后在运行时常量池中没有,所以调用intern()方法会将这个对象存入常量池中,并返回地址。所以str1 == str1.intern() 为true;
- 第二个:"java"在类加载机制过程中已经加载到常量池中,new出来的"java"对象与intern()方法从常量池返回的地址不一样,所以str2 == str2.intern() 为false;
- 第三个:与第一个是一样的,"abc"字符串new出来之后在运行时常量池中没有,所以调用intern()方法会将这个对象存入常量池中,并返回地址。所以str3 == str3.intern() 为true;;
- 第四个:String str4 = new StringBuilder("abc").toString()这个语句,首先会去常量池查找有没有“abc”这个字符串,有则只创建new StringBuilder("abc").toString()对象并把地址赋给str4,没有则创建“abc”和new StringBuilder("abc").toString()两个对象,所以不管如何,str4引用地址是指向new StringBuilder("abc").toString()这个新创建的对象,而str4.intern()返回的是“abc”的引用地址,str4 == str4.intern() 为false。