我有这样的情景 -
String s = "abc", t="abc"; //LINE 1
System.out.println(s==t); // definitely it would return true; //LINE 2
s=s+"d"; t=t+"d"; //LINE 3
System.out.println(s==t); // output would be false; but why??
s=s.intern(); t=t.intern();
System.out.println(s==t); // it would return true;
我想知道为什么第二个print语句返回false。请提供任何解释相同的参考链接。
在第1行创建t;实习生被召唤并指出“abc”为什么不在第3行召唤实习生?
答案 0 :(得分:6)
java字符串是immutable。
这意味着当您执行s=s+"d"
之类的操作时,实际上是在创建一个全新的字符串,并将其分配给s。
最重要的是,编译器会执行常量检测和分配,因此当您编写s="abc", t="abc"
时,编译器会重新使用相同的引用,并且您的代码实际上是s=t="abc"
所以你从完全相同的字符串实例开始(感谢编译器优化)并将其转换为2个相同但又不同的字符串,此时s==t
为假(s.equals(t)
为真,如它比较内容而不是内存中的地址。)
接下来是intern()。 intern()的作用是在字符串缓存中查找相同的字符串并返回它。如果它没有找到相同的条目,则将提供的参数放入缓存并返回参数。所以s=s.intern()
将s放入字符串缓存并返回它(因此s
保持不变),但以下调用t=t.intern()
实际返回s
,以便再次s==t
答案 1 :(得分:4)
String s = "abc", t="abc";
s == t
是true
,因为Java会自动实习String
个文字。在这种情况下,String
文字"abc"
已被实习,s
和t
都指向同一个实例。因此s == t
为true
。
s = s + "d"; t = t + "d";
Java中的字符串是不可变的。因此,您分配给s
和t
的内容是已构建的两个新 Strings
。因此,他们没有指向同一个实例。这就是s == t
返回false
。
s = s.intern(); t = t.intern();
在这里,你强行将s.intern()
中的字符串插入。由于s
和t
都包含相同的字符串值,因此JVM看到t
是相同的,并使其指向与s
相同的实例化实例。因此s == t
为true
。
总的来说,建立字符串相等应该通过.equals()
而不是==
完成; ==
仅比较引用类型的引用,而不是值。
答案 2 :(得分:4)
字符串是“特殊”的Java对象。
JVM尝试重用相同的引用(这就是String s = "abc", t="abc";
导致s
和t
指向同一实例的原因),但是,当处理实例时(例如t = t +) “d”)创建一个新实例,因此,引用不是相同的
为了比较字符串,您必须使用.equals()
方法。
intern()导致从String类中的字符串池中创建规范表示( http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#intern%28%29)
答案 3 :(得分:1)
Java语言规范明确涵盖了这种特殊情况。以下是chapter 3.10.5. "String Literals"的引用:
此外,字符串文字始终引用类String的相同实例。这是因为字符串文字 - 或者更常见的是常量表达式的值(第15.28节) - 是“实习”,以便使用String.intern方法共享唯一实例。 / p>
如您所见,只有常量表达式被实现。因此,代码的前四行等同于:
String s = "abc".intern(), t="abc".intern();
System.out.println(s==t);
s=s+"d".intern(); t=t+"d".intern();
System.out.println(s==t);
表达式s+"d"
和t+"d"
不是常量,因此不会被实习。
JLS甚至为an example提供了有用的注释。以下是相关部分:
package testPackage;
class Test {
public static void main(String[] args) {
String hello = "Hello", lo = "lo";
System.out.print((hello == ("Hel"+lo)));
}
}
输出:false 注意:在运行时通过串联计算的字符串是新创建的,因此是不同的。
答案 4 :(得分:0)
因为当你连接String
时,你会生成一个新的对象引用,除非它们是文字String
。
请注意,intern
的{{1}}指向同一个文字String
对象引用。