== 带字符串的运算符

2022-09-01 21:58:46

下面的代码不应该打印“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");
        }
    }
}

答案 1

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

字符串池(最初是空的)由类私下维护。String

调用该方法时,如果池中已包含与该方法确定的此对象相等的字符串,则返回池中的字符串。否则,此对象将添加到池中,并返回对此对象的引用。internStringequals(Object)StringString

因此,对于任何两个字符串 和 ,是当且仅当 为 true。sts.intern() == t.intern()trues.equals(t)

所有文本字符串和字符串值常量表达式都将被暂存。字符串文本在 Java 语言规范的 §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. 分配给 的文字会自动暂存,因此最终会引用池中的字符串。s1s1
  2. 分配给 的文字也是自动暂存的,因此最终指向同一实例指向。即使这两段代码可能彼此完全未知,这也很好,因为Java的实例是不可变的。您无法更改它们。您可以使用诸如取回具有更改的新字符串之类的方法,但是您调用的原始字符串(等)保持不变。因此,它们可以安全地在不相关的代码之间共享。s2s2s1StringtoLowerCasetoLowerCase
  3. 我们通过运行时操作创建一个新实例。即使新实例具有与实习实例相同的字符序列,它也是一个单独的实例。运行时不会自动插入动态创建的字符串,因为涉及成本:在池中查找字符串的工作。(而在编译时,编译器可以将该成本自行承担。所以现在我们有两个实例,一个指向,一个指向。因此,代码显示.Strings1s2s3s3 != s1
  4. 然后我们明确地实习.也许这是我们计划长期保留的一个大字符串,我们认为它可能会在其他地方复制。因此,我们接受实习它的工作,以换取潜在的内存节省。由于根据定义,实习意味着我们可以取回一个新的引用,因此我们将结果赋回给 。s3s3
  5. 我们可以看到,现在确实指向同一个实例并指向。s3s1s2

答案 2

硬编码的字符串被编译到JVM的字符串表中,该表保存唯一的字符串 - 即编译器仅存储“Hi”的一个副本,因此您正在比较相同的对象,因此可以正常工作。==

如果你实际上使用构造函数创建了一个新的 String,比如 new ,你会得到一个不同的对象。String("Hi")