Java 中字符串连接时的“==”

2024-03-12

String a = "devender";
String b = "devender";
String c = "dev";
String d = "dev" + "ender";
String e = c + "ender";

System.out.println(a == b);     //case 1: o/p true

System.out.println(a == d);     //case 2: o/p true

System.out.println(a == e);     //case 3: o/p false

a & b两者都指向字符串常量池中的相同字符串文字。所以true在情况1中

String d = "dev" + "ender";

应该在内部使用类似的东西:

String d = new StringBuilder().append("dev").append("ender").toString();

How a & d指向相同的引用而不是a & e ?


有四件事正在发生:

  1. (你显然知道这一点,但对于潜伏者来说)==测试变量是否指向same String object, not 相等的字符串。所以即使x is "foo" and y也是"foo", x == y可能是真的也可能是假的,取决于是否x and y参考相同的String对象或不同的对象。这就是为什么我们使用equals http://docs.oracle.com/javase/8/docs/api/java/lang/String.html#equals-java.lang.Object-, not ==,比较字符串是否相等。以下所有内容只是为了解释原因==有时是正确的,这不是建议使用==比较字符串。 :-)

  2. 同一类中的等效字符串常量(根据 JLS 中的各种规则,编译器知道是常量的字符串)由编译器引用相同的字符串(编译器还将它们列在类的“常量池” https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4)。这就是为什么a == b是真的。

  3. 当类被加载时,它的每个字符串常量都会自动interned http://docs.oracle.com/javase/8/docs/api/java/lang/String.html#intern--— 检查 JVM 的字符串池是否有等效字符串,如果找到,则表明String使用对象(如果没有,则使用新的String新常量的对象被添加到池中)。所以即使x是在类中初始化的字符串常量Foo and y是在类中初始化的字符串常量Bar,他们将是==彼此。

    上述第 2 点和第 3 点已部分涵盖JLS§3.10.5 https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5。 (关于类常量池的部分是一些实现细节,因此之前链接到了 JVM 规范;JLS 只是谈到了实习。)

  4. 如果编译器处理常量值,则会进行字符串连接,因此

    String d = "dev" + "ender";
    

    被编译为

    String d = "devender";
    

    and "devender"是编译器和 JVM 应用上面第 2 点和第 3 点的字符串常量。例如,不StringBuilder使用时,串联发生在编译时,而不是运行时。这涵盖在JLS§15.28 -常量表达式 https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.28. So a == d出于同样的原因也是如此a == b为 true:它们引用相同的常量字符串,因此编译器确保它们引用类常量池中的相同字符串。

    当任何操作数不是常量时,编译器无法执行此操作,因此它不能使用以下命令执行此操作:

    String e = c + "ender";
    

    ...尽管代码分析可以很容易地表明c肯定会"dev"因此e肯定会"devender"。具体而言,规范仅让编译器与常量值进行串联。因此,由于编译器无法执行此操作,因此它输出StringBuilder您提到的代码并且工作是在运行时完成的,创建一个新的String目的。该字符串不会自动保留,所以e最终指的是不同的String对象比a确实如此,所以a == e是假的。

    注意正如维诺德所说 https://stackoverflow.com/questions/34509566/in-case-of-string-concatenation-in-java/34509659#comment56760592_34509566,如果你声明c as final:

    final String c = "dev";
    

    那么这将是一个常数变量 https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.12.4(是的,它们确实是这样称呼的),因此 §15.28 将适用,编译器将变成

    String e = c + "ender";
    

    into

    String e = "devender";
    

    and a == e也将是真的。

只是重申一下:这并不意味着我们应该使用==比较字符串是否相等。 :-) 就是这样equals is for.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 中字符串连接时的“==” 的相关文章

随机推荐