这串java代码分别会输出什么值,分别解释原因,根据¹²³,Java中的字符串有两种存储方式:堆(heap)和常量池(constant pool)。堆是用来存储动态创建的字符串对象的,每个字符串对象都有自己的内存地址。常量池是用来存储静态创建的字符串字面量的,相同内容的字符串字面量只会在常量池中存在一份,并且可以被多个引用指向(重点)。Java中的 == 运算符是用来比较两个引用是否指向同一个对象的,而不是比较两个字符串的内容是否相等。如果要比较两个字符串的内容是否相等,需要使用equals方法。

String类提供了一个intern方法,它可以返回一个字符串在常量池中的引用。如果常量池中已经存在一个相同内容的字符串,则直接返回它的引用;如果不存在,则在常量池中创建一个新的字符串,并返回它的引用。

根据这些知识,我们可以分析这串java代码:

public class Test {
    public static void main(String[] args) {
        String s1 = "Programming"; // 常量池
        String s2 = new String("Programming"); // 堆
        String s3 = "Program";
        String s4 = "ming";
        String s5 = "Program" + "ming";
        String s6 = s3 + s4;
        System.out.println(s1 == s2); // 比较s1和s2是否指向同一个对象 false
        System.out.println(s1 == s5); // 比较s1和s5是否指向同一个对象 true
        System.out.println(s1 == s6); // 比较s1和s6是否指向同一个对象 false
        System.out.println(s1 == s6.intern()); // 比较s1和s6在常量池中的引用是否相同 true
        System.out.println(s2 == s2.intern()); // 比较s2和s2在常量池中的引用是否相同 false
    }
}

输出结果:

false
true
false
true
false

解释原因:

  • 第一行输出false,因为s1是从常量池中获取”Programming”字面量的引用,而s2是在堆上(动态对象) 创建了一个新的”Programming”对象,并获取它的引用。所以它们指向不同的对象。
  • 第二行输出true,因为s5是由两个字面量拼接而成,在编译期就已经确定为”Programming”字面量,并从常量池中获取它的引用。所以它和s1指向同一个对象。
  • 第三行输出false,因为s6是由两个变量拼接而成,在运行期才能确定其值,并在堆上创建了一个新的”Programming”对象,并获取它的引用。所以它和s1指向不同的对象。
  • 第四行输出true,因为调用了intern方法后,会返回”Programming”在常量池中已经存在了一份并且被多个引用指向(包括s1)。
  • 第五行输出false,因为调用了intern方法后,会返回”Programming”在常量池中已经存在了一份并且被多个引用指向(包括s1),但是不包括原来堆上创建时获取到得那份(即使他们内容相等)。

源: 与必应的对话, 2023/3/9(1) Java.String.intern() | Baeldung. https://www.baeldung.com/string/intern 访问时间 2023/3/9. (2) Java String intern() method - javatpoint. https://www.javatpoint.com/java-string-intern 访问时间 2023/3/9. (3) What is Java String interning? - Stack Overflow. https://stackoverflow.com/questions/10578984/what-is-Java-string-interning 访问时间 2023/3/9.