之前从未使用过Java,我在教自己泛型语法。我用一些字符串测试了简单的泛型函数,并注意到一些有点奇怪的东西:
public class Main {
public static <T> boolean areSameReference(T lhs, T rhs) {
return lhs == rhs;
}
public static void main(String[] args) {
String s = new String("test1");
String t = s;
String u = new String("test1");
System.out.println(areSameReference(s, t)); //true
System.out.println(areSameReference(s, u)); //false
String v = "test2";
String w = "test2";
System.out.println(areSameReference(v, w)); //true
}
}
为什么[s]和[u]是不同的参考文献,但[v]和[w]是相同的参考文献?我想如果有或没有“new”,字符串文字会导致它们在两种情况下都一致或不同。
我错过了其他的事情吗?
答案 0 :(得分:4)
为什么[s]和[u]是不同的参考,
因为您告诉编译器您想要新字符串,不是吗?
答案 1 :(得分:3)
字符串文字始终引用类String的相同实例。 这是因为字符串文字 - 或者更常见的是字符串 常量表达式的值(§15.28) - 被“实施”以便 使用String.intern。
方法共享唯一实例
String v = "test2";
String w = "test2";
将被视为字符串文字。
当您使用 new 运算符构造String
对象时,它会分配新的String对象。
答案 2 :(得分:1)
使用new,您可以调用内存管理系统并获取新对象。
如果没有new,编译器会将字符串内容优化为“.class”常量表中的一个条目,从而导致对“.class”常量表中相同条目的两次访问。
Java中的=
比较运算符是一个参考比较运算,因此您将看到这两种技术之间的差异。您可以通过充分使用String.intern(otherString)
来隐藏这些差异。
这里带回家的教训是,除非在极端情况下,始终使用.equals(...)
与对象进行比较。
答案 3 :(得分:1)
JVM保留一个字符串池,这样就不会浪费具有重复字符串的内存。因此,v
和w
应该相同。我猜你所遇到的行为是由new String(String original)
构造函数中隐含的契约引起的,这表明它创建了一个新对象(参见http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/String.html#String(java.lang.String))。
答案 4 :(得分:1)
String对象是不可变的,其中字符串引用是可变的。定义“s”和“u”时,会创建每个新对象。这里的值无关紧要,因为您调用构造函数,但是当您为不同的String对象分配相同的值时,它们将成为对内存中相同“test2”对象的引用。
我建议在Java中阅读更多有关不可变对象的内容,这里有一篇好文章: http://javarevisited.blogspot.com/2010/10/why-string-is-immutable-in-java.html