在Java中编译时是否完成了字符串实习?

我真的很困惑字符串实习在Java中是如何工作的。 我写的时候:

String a = "ABC"; String b = "ABC"; if (a==b) System.out.println("Equal"); 

编译时编译器是否将字符串文字“ABC”存储到字符串常量池中?

这听起来不合逻辑,因为我认为字符串常量池是由JVM在运行时创建的,我不知道如果在编译时完成它是如何可能的,因为Java编译器甚至不调用JVM。

如果它没有在编译时完成并且它在运行时完成,那么为什么以下返回false(取自此答案 )?

 // But .substring() is invoked at runtime, generating distinct objects "test" == "!test".substring(1) // --> false 

如果它是在运行时完成的,为什么JVM不能确定它们是相同的字符串?

我真的很困惑字符串实习如何在Java中工作以及Java字符串池的存储位置。

编译器将文字字符串放在类文件中(并且只有唯一的字符串,它会合并所有等效的文字); 加载类文件时,JVM将这些字符串加载到字符串池中。

如果它是在运行时完成的,那么为什么JVM不能确定它们是相同的String。

因为.substring返回的字符串尚未被实现,因此与字符串池中的等效"test"字符串不同。 如果你实习,你就会成true

 "test" == "!test".substring(1).intern() // true 

JLS的第4.4节和JVM规范的第5.3节看起来很相关。


需要明确的是:在Java中比较字符串的正确方法是使用.equals方法或类似方法,而不是== 。 在字符串实例中使用== 通常是不正确的。 (除非你正在了解事情被拘禁的时间和方式……)

我检查了.class

 String a = "ABC"; String b = "ABC"; 

并且发现其中只有一个“ABC”。 那就是javac在编译时创建了一个相同字符串的常量。

但是,如果2个或更多类具有相同的“ABC”常量,则JVM将它们放在字符串池中的相同位置