使用字符串的==运算符

Ock*_*zor 23 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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

T.J*_*der 42

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

最初为空的字符串池由类私有维护String.

intern被调用的方法,如果池已经包含一个字符串等于该String由测定对象equals(Object)的方法,然后从池中字符串被返回.否则,将此String对象添加到池中,并String返回对此对象的引用.

它遵循对于任何两个字符串st,s.intern() == t.intern()true当且仅当s.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";
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

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

走过那个:

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

  • @Ockhams:很高兴有帮助.是的,该链接中的示例是错误的(如果作者只是尝试过,他/她就会知道),但仅仅因为该示例使用文字和文字(以及其他常量字符串表达式)会自动实现.该帖子的总点,即字符串是对象,所以如果你想比较它们以查看它们是否具有相同的字符,你使用`equals`而不是`==`,是正确的.但当然这个例子是完全错误的. (3认同)

Boh*_*ian 10

硬编码字符串被编译到JVM的字符串表中,字符串表包含唯一的字符串 - 即编译器只存储一个"Hi"的副本,因此您正在比较同一个对象,因此==有效.

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