为什么 Java 字符串比较在 Java 15 和 Java 11 中表现不同?

Why does a Java string comparison behave different in Java 15 and Java 11?

请考虑以下内容class:

class Eq {
  public static void main(String[] args) {
    System.out.println("" == ".".substring(1));
  }
}

该示例应该表明内存中可能存在空字符串的多个副本。我仍然有一个旧的 OpenJDK 11,其中程序按预期输出 false。在 OpenJDK 15 下,程序输出 true。 class 文件生成的字节码看起来很相似(尽管它们的寄存器值不同):

Java 11:

public static void main(java.lang.String[]);
  Code:
     0: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
     3: ldc           #13                 // String
     5: ldc           #15                 // String .
     7: iconst_1
     8: invokevirtual #17                 // Method java/lang/String.substring:(I)Ljava/lang/String;
    11: if_acmpne     18
    14: iconst_1
    15: goto          19
    18: iconst_0
    19: invokevirtual #23                 // Method java/io/PrintStream.println:(Z)V
    22: return

Java 15:

public static void main(java.lang.String[]);
  Code:
     0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
     3: ldc           #3                  // String
     5: ldc           #4                  // String .
     7: iconst_1
     8: invokevirtual #5                  // Method java/lang/String.substring:(I)Ljava/lang/String;
    11: if_acmpne     18
    14: iconst_1
    15: goto          19
    18: iconst_0
    19: invokevirtual #6                  // Method java/io/PrintStream.println:(Z)V
    22: return

我试图通过读取“.”来排除静态编译器优化。来自 stdin 但这不会改变结果。我试图通过 -Djava.compiler=NONE 禁用 JIT,并尝试通过 -XX:StringTableSize=100000 调整字符串 table 的大小。我现在有以下问题:

我认为只是解决如何找到未回答问题的行为的原因的策略也可能很有趣。

这个在JDK 15 Release Notes.

中有提到

已根据 JDK-8240094 的要求更改:

JDK-8240094 : Optimize empty substring handling

String.substring return "" in some cases, but could be improved to do so in all cases when the substring length is zero.

相关:

JDK-8240225 : Optimize empty substring handling

Optimize String.substring and related operations like stripLeading, stripTrailing to avoid redundantly creating a new empty String.

子任务:

JDK-8251556 : Release Note: Optimized Empty Substring Handling

The implementation of String.substring and related methods stripLeading and stripTrailing have changed in this release to avoid redundantly creating a new empty String. This may impact code that depends on unspecified behaviour and the identity of empty sub-strings.