&引用==&引用;在Java中进行字符串连接的情况下
a和b都指向字符串常量池中的相同字符串文本。因此,在案例1中&引用==&引用;在Java中进行字符串连接的情况下,java,string,Java,String,a和b都指向字符串常量池中的相同字符串文本。因此,在案例1中true String a = "devender"; String b = "devender"; String c = "dev"; String d = "dev" + "ender"; String e = c + "ender"; System.out.println(a == b); //case
true
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
应该在内部使用类似于:
String d = "dev" + "ender";
a&d是如何指向同一引用的&而不是a&e?正如您在内部所说,最后一次连接是针对类似于
String d = new StringBuilder().append("dev").append("ender").toString();
StringBuilder
的toString()
的实现创建了一个新字符串。下面是实现
String e = new StringBuilder().append(c).append("ender").toString();
仅当两个字符串相同时,使用==
而不是.equals()
比较字符串会返回true
。在这种情况下,它们是不同的,因为第二个字符串是作为类型为string
的新对象创建的
其他连接由编译器直接执行,因此不会创建新字符串。发生了四件事:
=
测试变量是否指向相同的字符串,而不是等价的字符串。因此,即使x
是“foo”
并且y
也是“foo”
,x==y
可能是真或假,这取决于x
和y
是指相同的字符串对象还是指不同的对象。这就是为什么我们使用而不是==
,来比较字符串的等价性。以下所有内容只是为了解释为什么=
有时是正确的,并不建议使用=
来比较字符串。:-)
a==b
是正确的string
对象(如果没有,则将新常量的新string
对象添加到池中)。因此,即使x
是在类Foo
中初始化的字符串常量,y
是在类Bar
中初始化的字符串常量,它们也将彼此=
上文第2点和第3点在本节的部分内容中有介绍。(关于类常量池的部分是一个实现细节,因此前面有到JVM规范的链接;JLS只提到了interning。)public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
编译为
String d = "dev" + "ender";
而“devender”
是编译器和JVM应用上述第2点和第3点的字符串常量。例如,如果不使用StringBuilder
,则连接发生在编译时,而不是运行时。这是一本书。因此a==d
为true,原因与a==b
为true相同:它们引用相同的常量字符串,因此编译器确保它们引用的是类的常量池中的相同字符串
当任何操作数不是常量时,编译器都无法执行此操作,因此在以下情况下无法执行此操作:
String d = "devender";
…即使代码分析可以很容易地表明c
的值肯定是“dev”
,因此e
肯定是“devender”
。该规范只让编译器使用常量值进行连接,具体来说。因此,由于编译器无法执行此操作,它将输出您提到的StringBuilder
代码,并且该工作将在运行时完成,从而创建一个新的String
对象。该字符串不会自动插入,因此e
最终引用的string
对象与a
不同,因此a==e
为false
请注意,如果您将c
声明为final
:
String e = c + "ender";
然后是a(是的,它们真的被称为a),因此§15.28将适用,编译器将
final String c = "dev";
进入
而且a==e
也是正确的=
来比较字符串的等价性。:-)这就是equals
的作用。“dev”+“ender”
是一个编译时可计算的常量表达式:两个参数都是字符串文本。因此,表达式是“devender”
对于c+“ender”
,情况并非如此:某些情况(例如,某些代码在不同线程上运行)可能会导致c
被设置为不同的值。将c
限定为final
可以避免这种可能性,在这种情况下e
也将引用与a
相同的对象
因此
a
、b
和d
都指向同一个对象。d和e
之间的区别在于,当您连接字符串文本时,连接是在编译时执行的。Java编译器处理“dev”+“ender”
表达式的方式与处理“devender”
表达式的方式相同,在编译时生成相同的文本。由于所有String
文本都被插入,d
,这是“dev”+“ender”
的结果,也最终引用了与a
和b
的“devender”
相同的对象
e
的表达式是c+“ender”
,在运行时进行计算。即使它生成相同的字符串,编译器也不会使用这个事实。这就是为什么会生成不同的字符串
对象,导致在=
上的比较失败。编译器会在后台进行大量优化
这里是编译器wil
String e = c + "ender";
String e = "devender";
String d = "dev" + "ender";
String d = "dev" + "ender";
0: ldc #16 // String devender
final String c = "dev"; // mark this as final
String e = c + "ender";