3

以前从未使用过 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] 是相同的引用?我原以为无论有没有“新”,字符串文字都会导致它们在两种情况下始终相同或不同。

我错过了这里发生的其他事情吗?

4

5 回答 5

4

为什么 [s] 和 [u] 是不同的引用,

因为你告诉编译器你想要的字符串,不是吗?

于 2013-03-12T21:22:28.947 回答
3

根据JLS 3.10.5

字符串字面量总是引用 String 类的同一个实例。这是因为字符串字面量 - 或者更一般地说,作为常量表达式值的字符串(第 15.28 节) - 是“内部的”,以便使用 String.intern 方法共享唯一实例。

     String v = "test2";
     String w = "test2";

将被视为字符串文字。

当您使用new运算符构造String对象时,它会分配新的 String 对象。

于 2013-03-12T21:18:55.643 回答
1

JVM 保留一个字符串池,这样它就不会因为重复的字符串而浪费内存。因此,vw应该是一样的。我猜您遇到的行为是由于new String(String original)构造函数中隐含的合同,这表明它创建了一个新对象(请参阅http://docs.oracle.com/javase/1.5.0/docs/ api/java/lang/String.html#String(java.lang.String))。

于 2013-03-12T21:22:12.227 回答
1

字符串对象是不可变的,其中字符串引用是可变的。当您定义“s”和“u”时,将为每个创建新对象。这里的值无关紧要,因为您调用构造函数,但是当您将相同的值分配给不同的 String 对象时,它们将成为对内存中相同“test2”对象的引用。

我建议阅读更多关于 Java 中不可变对象的信息,这里有一篇好文章:http: //javarevisited.blogspot.com/2010/10/why-string-is-immutable-in-java.html

于 2013-03-12T21:30:47.900 回答
1

使用 new,您可以调用内存管理系统并获取一个新对象。

如果没有 new,编译器会将字符串内容优化为“.class”常量表中的一个条目,从而导致对“.class”常量表中的同一条目进行两次访问。

Java 中的=比较运算符是参考比较操作,因此您会看到两种技术之间的差异。您可以通过充分使用String.intern(otherString).

这里要带回家的教训是,除非在极端情况下,否则总是使用.equals(...)to compare to objects

于 2013-03-12T21:20:48.623 回答