Java中的字符串串联时的“==”

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (14)
    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

ab都指向字符串常量池中相同的字符串文字。所以true在案例1中

String d = "dev" + "ender";

应该在内部使用类似于 -

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

如何一个d都指向相同的参考及不能ê

提问于
用户回答回答于

四件事情正在发生:

  1. (你清楚地知道这一点,但对于潜伏者)==测试,看看变量是否指向同一个String对象,而不是等价的字符串。所以,即使x"foo"y"foo"x == y可能是真的还是假的,这取决于是否xy指向同一个String对象或不同的。这就是为什么我们使用equals,不==,比较字符串的等价。以下所有内容仅仅是为了解释为什么==有时会出现这种情况,并不是==用来比较字符串的建议。:-)
  2. 在同一个类中,等价的字符串常量(编译器知道的字符串是根据JLS中的各种规则的常量)被编译器引用相同的字符串(它们也在类的“常量池”中列出它们)。这就是为什么a == b是真的。
  3. 当类被加载,它的每一个字符串常量自动扣留 - JVM的字符串池检查等效字符串,如果找到一个,即String使用对象(如果没有,新String的恒新对象添加到池)。所以,即使x是在类中初始化的字符串常量,Foo并且y是在类中初始化的字符串常量Bar,它们也将是==彼此的。 以上第2点和第3点部分由JLS§3.10.5覆盖。(关于类常量池的一点是实现细节的一小部分,因此与之前的JVM规范有关; JLS只是提到了实习。)
  4. 如果编译器处理常量值,编译器会执行字符串连接,所以 String d = "dev" + "ender"; 被编译为 String d = "devender"; 并且"devender"是一个字符串常量,编译器和JVM将上面的点2和3应用于。例如,使用no StringBuilder,连接发生在编译时,而不是运行时。这包含在JLS§15.28 - 常量表达式中。所以a == d是真正出于同样的原因a == b是正确的:它们指向同一个常量字符串,所以编译器确保他们指的在类的常量池相同的字符串。 当任何操作数不是一个常量时,编译器不能这样做,所以它不能这样做: String e = c + "ender"; ...即使代码分析可以很容易地表明,价值c肯定会是"dev",因此e一定会"devender"。该规范仅具有编译器与常量值进行连接,具体而言。因此,由于编译器无法执行它,它会输出StringBuilder您引用的代码,并且该工作在运行时完成,从而创建一个新String对象。该字符串不会自动实现,因此e最终引用的String对象不是a这样,所以a == e是false。 请注意,正如Vinod所说,如果您声明cfinalfinal String c = "dev"; 然后它将是一个常量变量(是的,他们真的被称为),所以第15.28节将适用,编译器将转向 String e = c + "ender"; String e = "devender"; 并且a == e也将是如此。

只是重申:没有哪一个意味着我们应该使用==比较字符串的等价性。:-)就是这样equals

用户回答回答于

编译器在底层做了很多优化。

String d = "dev" + "ender";

在这里,编译器将取代"dev" + "ender""devender"被编译的程序时。如果要添加2个文字(这适用于基元和字符串),编译器会执行此优化。

Java代码:

String d = "dev" + "ender";

字节码:

  0: ldc           #16                 // String devender

来一个特例:

final String c = "dev"; // mark this as final String e = c + "ender";

进行c最后的操作会使字符串成为编译时常数。编译器会意识到,值c不能改变,因此在编译时会用c“dev”值替换所有的值,因此e编译时本身就会解决。

扫码关注云+社区