我对string interning在Java中的工作原理感到困惑。我写的时候:
String a = "ABC";
String b = "ABC";
if (a==b)
System.out.println("Equal");
编译器是否在编译时将字符串文字“ABC”存储到字符串常量池中?
这听起来不合逻辑,因为我认为字符串常量池是由JVM在运行时创建的,如果它是在编译时完成的,我不知道如何这样做,因为Java编译器甚至没有调用JVM。
如果它没有在编译时完成并且在运行时完成,那么为什么以下返回false(取自this answer)?
// But .substring() is invoked at runtime, generating distinct objects
"test" == "!test".substring(1) // --> false
如果在运行时完成,为什么JVM不能确定它们是相同的字符串?
我真的很困惑字符串实习如何在Java中工作以及Java字符串池的存储位置。
答案 0 :(得分:19)
编译器将文字字符串放在类文件中(并且只有唯一的字符串,它会整合所有等效的文字);加载类文件时,JVM将这些字符串加载到字符串池中。
如果在运行时完成,那么为什么JVM不能确定它们是相同的String。
因为.substring
返回的字符串尚未被中断,因此与字符串池中的等效"test"
字符串不同。如果你实习,你会得到true
:
"test" == "!test".substring(1).intern() // true
§4.4 of the JLS和§5.3 of the JVM spec部分看起来很相似。
要明确:在Java中比较字符串的正确方法是使用.equals
方法或类似方法,而不是==
。将==
与字符串实例一起使用通常不正确。 (除非你正在了解事情被拘禁的时间和方式......)
答案 1 :(得分:0)
我检查了.class
String a = "ABC";
String b = "ABC";
并且发现其中只有一个“ABC”。那就是javac在编译时创建了一个相同字符串的常量。
但是如果2个或更多类具有相同的“ABC”常量,那么JVM会将它们放在字符串池中的相同位置