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
in case 1
String d = "dev" + "ender";
应该在内部使用类似的东西:
String d = new StringBuilder().append("dev").append("ender").toString();
a 和 d 如何指向同一个引用而不是 a 和 e ?
最佳答案
正在发生四件事:
(你清楚地知道这一点,但对于潜伏者)
==
测试变量是否指向相同的String
对象,而不是等效字符串。所以即使x
是"foo"
并且y
也是"foo"
,x == y
可能是 true 或 false,这取决于x
和y
是指相同的String
对象还是不同的对象。这就是我们使用equals
的原因。 ,而不是==
,来比较字符串是否相等。以下所有内容只是为了解释为什么==
有时为真,不建议使用==
来比较字符串。 :-)同一个类中的等价字符串常量(编译器知道的字符串是根据 JLS 中的各种规则的常量)由编译器引用同一个字符串(它也在类的 "constant pool" 中列出了它们) )。这就是
a == b
为真的原因。加载类时,其每个字符串常量自动为interned — 检查 JVM 的字符串池中是否存在等效字符串,如果找到,则使用该
String
对象(如果没有,则添加新常量的新String
对象到游泳池)。所以即使x
是在类Foo
中初始化的字符串常量,而y
是在类Bar
中初始化的字符串常量,它们将是==
彼此。以上第 2 点和第 3 点已被 JLS§3.10.5 部分覆盖。 . (关于类常量池的部分是一个实现细节,因此链接到前面的 JVM 规范;JLS 只是谈到实习。)
编译器在处理常量值时会进行字符串连接,所以
String d = "dev" + "ender";
编译成
String d = "devender";
and
"devender"
是一个字符串常量,编译器和 JVM 将上面的第 2 点和第 3 点应用到。例如,没有使用StringBuilder
,连接发生在 compile-time,而不是运行时。这在 JLS§15.28 - Constant Expressions 中有介绍.所以a == d
为 true 的原因与a == b
为 true 的原因相同:它们引用相同的常量字符串,因此编译器确保它们引用的是相同的类常量池中的字符串。当任何操作数不是常量时,编译器不能这样做,所以它不能这样做:
String e = c + "ender";
...即使代码分析很容易表明
c
的值肯定是"dev"
并且因此e
肯定会是“开发者”
。具体来说,规范只让编译器与常量值进行连接。因此,由于编译器无法执行此操作,它会输出您引用的StringBuilder
代码,并且该工作在运行时完成,创建一个新的String
对象。该字符串不会自动被保留,因此e
最终会引用与a
不同的String
对象,因此a = = e
为假。请注意 as Vinod said , 如果您将
c
声明为final
:final String c = "dev";
那么它将是 constant variable (是的,它们确实被称为),因此 §15.28 将适用,编译器将转向
String e = c + "ender";
进入
String e = "devender";
和
a == e
也是如此。
重申一下:这些都不意味着我们应该使用 ==
来比较字符串的等价性。 :-) 这就是 equals
的用途。
关于java - "=="在 Java 中字符串连接的情况下,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34509566/