使用字符串的==运算符

时间:2011-07-05 07:51:36

标签: java string

下面的代码不应该打印“Bye”,因为==运算符用于比较引用,但奇怪的是,仍然会打印“Bye”。为什么会这样?我正在使用Netbeans 6.9.1作为IDE。

public class Test {
    public static void main(String [] args) {
        String test ="Hi";
        if(test=="Hi"){
            System.out.println("Bye");
        }
    }
}

4 个答案:

答案 0 :(得分:42)

此行为是因为实习String#intern的文档中描述了这种行为(包括为什么它会显示在您的代码中,即使您从未调用String#intern):

  

字符串池(最初为空)由类String私有维护。

     

当调用intern方法时,如果池已经包含等于String方法确定的equals(Object)对象的字符串,则返回池中的字符串。否则,将此String对象添加到池中,并返回对此String对象的引用。

     

对于任何两个字符串st,当{且仅s.intern() == t.intern()为真时,trues.equals(t)

     

所有文字字符串和字符串值常量表达式都是实体。字符串文字在Java Language Specification的§3.10.5中定义。

例如:

public class Test {

    private String s1 = "Hi";

    public static void main(String [] args) {

        new Test().test();
        System.exit(0);
    }

    public void test() {
        String s2 ="Hi";
        String s3;

        System.out.println("[statics]          s2 == s1? " + (s2 == s1));
        s3 = "H" + part2();
        System.out.println("[before interning] s3 == s1? " + (s3 == s1));
        s3 = s3.intern();
        System.out.println("[after interning]  s3 == s1? " + (s3 == s1));
        System.exit(0);
    }

    protected String part2() {
        return "i";
    }
}

输出:

[statics]          s2 == s1? true
[before interning] s3 == s1? false
[after interning]  s3 == s1? true

走过那条:

  1. 分配给s1的字面值会自动实现,因此s1最终会引用池中的字符串。
  2. 分配给s2的文字也是自动实习的,因此s2最终指向同一个实例s1。这很好,即使代码的两位代码可能彼此完全不知道,因为Java的String实例是不可变的。你无法改变它们。您可以使用toLowerCase之类的方法来获取带有更改的 new 字符串,但您调用toLowerCase(等)的原始字符串保持不变。因此,他们可以安全地在不相关的代码中共享。
  3. 我们通过运行时操作创建 new String实例。即使新实例与实际实例具有相同的字符序列,它也是单独的实例。运行时不会自动动态创建字符串,因为涉及成本:在池中查找字符串的工作。 (编译时,编译器可以将该成本转嫁给自己。)现在我们有两个实例,一个s1s2指向,一个s3指向。因此代码显示s3 != s1
  4. 然后我们明确实习s3。也许这是我们计划长期坚持的大字符串,我们认为它可能会在其他地方重复出现。因此,我们接受实习的工作,以换取潜在的内存节省。由于按定义进行实习意味着我们可能会返回新的参考,我们会将结果分配回s3
  5. 我们可以看到,s3现在确实指向同一个实例s1s2指向。

答案 1 :(得分:10)

硬编码字符串被编译到JVM的String Table中,该表包含唯一的字符串 - 即编译器只存储一个“Hi”副本,因此您要比较同一个对象,所以{ {1}}有效。

如果您实际使用构造函数创建新String,例如新==,则获取另一个对象。

答案 2 :(得分:1)

java中有一个String缓存。在这种情况下,从具有相同引用的缓存返回相同的对象。

答案 3 :(得分:0)

主要原因是"Hi"String Pool中获取。不可变对象必须具有某种缓存,以便它可以更好地执行。所以String类是不可变的,它使用String Pool进行基本缓存。

在这种情况下,"Hi"位于字符串池中,所有值为"Hi"的字符串对字符串池都具有相同的引用。