我写了以下代码:
String s="Rahul";
String s2=s.concat(" Shukla");
String s3="Rahul Shukla";
System.out.println(s2==s3);
我期望s2 == s3的输出为true,但它变为false。因为我认为s2和s3指向字符串常量池中的同一个对象,所以s2 == s3应该计算为true。谁能告诉我这里到底发生了什么?
答案 0 :(得分:3)
首先,除非您关心JVM内部和不可靠的“保证”,否则请不要使用==
。只是不要。
其次,当使用“Shukla”调用concat
时,结果是常量池中的不。 Rahul
和Shulka
是,但它们的连接是堆上的新String:
在运行时通过串联计算的字符串是新创建的,因此是不同的。
+
作为运算符是不同的,因为它不是方法调用,在它的两个操作数都是常量的情况下(通过字符串文字):
由常量表达式计算的字符串(第15.28节)在编译时计算,然后将其视为文字。
同一个包(第7节(包))中同一个类(第8节(类))中的文字字符串表示对同一个String对象的引用(§4.3.1)。
所有引号均来自JLS, Version 8, section 10.3.5。
答案 1 :(得分:0)
如果你使用新的String(somestring).intern()创建了每个字符串,那么你可以使用==运算符来比较两个字符串,否则只能使用equals()或compareTo方法。 equals()方法存在于java.lang.Object类中,它应该检查对象状态的等价性。
答案 2 :(得分:0)
由于String是不可变的concat()
方法,因此将创建新的字符串对象。但s3
将引用字符串池中的对象。所以s2==s3
它将返回false
答案 3 :(得分:0)
s3
变量在池中创建,而s2
在堆中创建,因为==
比较了不相等的引用,这给了你错误。
String s3="Rahul Shukla";
是否可以在编译时确定s3
值中的创建者
String s2=s.concat(" Shukla");
是在堆中创建的,因为如果您看到concat()
的源代码,则会返回new String()
答案 4 :(得分:0)
有趣的是,VirtualProtect()
的规范在Java 7和Java 8之间发生了变化。
如果参数字符串的长度为0,则返回此String对象。否则,将创建新的String对象 ...
如果参数字符串的长度为0,则返回此String对象。否则,返回一个String对象,该对象表示一个字符序列,该字符序列是由此String对象表示的字符序列和由参数字符串表示的字符序列的串联。
但是,实施似乎没有改变。这是代码。
concat
这意味着,如果您使用public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
将==
的结果与s.concat(" Shukla")
进行比较,则会得到s3
,但严格来说,规范并未保证这一点。
然而,正如其他人所指出的那样,你不需要关心这一点。您应该使用false
比较字符串,并忘记详细信息。