题目

public class Test {
    public static void main(String[] argss) {
        String str1 = new StringBuilder("58").append("tongcheng").toString();
        System.out.println(str1);
        System.out.println(str1.intern());
        System.out.println((str1 == str1.intern()));
        System.out.println();
        String str2 = new StringBuilder("ja").append("va").toString();
        System.out.println(str2);
        System.out.println(str2.intern());
        System.out.println((str2 == str2.intern()));
    }
}

运行结果

58tongcheng
58tongcheng
true

java
java
false

原因

  • String str1在方法里创建了一个变量,new StringBuilder(“58”)在堆内存中创建了对象,调用对象的append方法,把这个StringBuilder里的字符串加成了"58tongcheng",然后调用toString创建并返回了一个String对象,这个返回的String对象仍然在堆内存里,str1指向了这个String对象。
  • 打印str1
  • 调用字符串的intern方法,前往常量池中查询是否存在这个字符串,发现没有存在,则将该字符串对象加入了常量池中,并返回了该字符串对象。(String对象,内容为:“58tongcheng”)
  • 判断str1和str1.intern()是否相等,也就是判断str1指向的对象和常量池中"58tongcheng"这个字符串对应的对象的地址是否相同,由于前面调用的时候把这个字符串对象加入进了常量池,因此这次返回的其实还是str1之前指向的那个String对象,判断这两个String对象地址是否相等返回true
  • 打印空行
  • String str2在方法里创建了一个变量,new StringBuilder(“ja”)在堆内存中创建了对象,调用对象的append方法,把这个StringBuilder里的字符串加成了"java",然后调用toString创建并返回了一个String对象,这个返回的String对象仍然在堆内存里,str1指向了这个String对象。
  • 打印str1
  • 调用字符串的intern方法,前往常量池中查询是否存在这个字符串,发现存在,存在的原因是,java默认加载了java.lang包下的所有类,而String类就在这个包下,因此加载类的时候这个java字符串是一个包名,已经被加载进了String类的静态常量池了,那么这次打印的是常量池中的"java"字符串对应的String对象。(String对象,内容为:“java”)
  • 判断str1和str1.intern()是否相等,也就是判断str1指向的对象和常量池中"java"这个字符串对应的对象的地址是否相同,由于前面调用的时候这个字符串对象是新创建的存在于堆内存中的,调用intern方法返回的String对象是之前在加载java.lang下的String类时就已经被加载进了String类的常量池了的,因此两个String对象内存地址不相等返回false。