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

2022-09-01 14:31:39

请考虑以下类:

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

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

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中读取“.”来排除静态编译器优化,但这不会改变结果。我尝试通过禁用JIT,并通过调整字符串表大小进行了尝试。我现在有以下问题:-Djava.compiler=NONE-XX:StringTableSize=100000

  • 有人可以重现问题吗(即我是否正确执行了该问题?如果有帮助,我可以提供类文件)
  • 我如何找出不同行为的确切原因?
  • (在你看来)不同行为的来源是什么?

我认为,仅仅找到没有回答问题的行为原因的策略也可能很有趣。


答案 1

这在 JDK 15 发行说明中有所提及。

它已根据 JDK-8240094 的要求进行了更改:

JDK-8240094 : 优化空子字符串处理

String.substring在某些情况下返回,但可以改进为在所有情况下,当子字符串长度为零时,都可以这样做。""

相关:

JDK-8240225 : 优化空子字符串处理

优化和相关操作,如 ,以避免冗余创建新的空字符串。String.substringstripLeadingstripTrailing

子任务:

JDK-8251556:版本说明:优化的空子字符串处理

此版本中的 实现和相关方法已更改,以避免冗余创建新的空字符串。这可能会影响依赖于未指定行为和空子字符串标识的代码。String.substringstripLeadingstripTrailing


答案 2