在 Java 中,字符串暂存是在编译时完成的吗?

2022-09-03 14:04:51

我对字符串实习在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字符串池的确切存储位置感到非常困惑。


答案 1

编译器将文本字符串放在类文件中(并且仅是唯一的字符串,它合并所有等效的文本);在装入类文件时,JVM 将这些字符串装入字符串池中。

如果它是在运行时完成的,那么为什么JVM不能弄清楚它们是相同的字符串。

因为 返回的字符串尚未被暂存,因此与字符串池中的等效字符串是不同的对象。如果你实习它,你会得到:.substring"test"true

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

JLS 的 §4.4 节和 JVM 规范的 §5.3 部分看起来是相关的。


需要明确的是:在Java中比较字符串的正确方法是使用方法或类似方法,而不是。与字符串实例一起使用通常不正确。(除非你正在尝试了解何时以及如何被拘留......).equals====


答案 2

我检查了.class

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

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

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