代码之家  ›  专栏  ›  技术社区  ›  e2rabi

对本例中的字符串比较感到困惑

  •  0
  • e2rabi  · 技术社区  · 5 年前

    我知道“==”比较引用和java字符串是不可变的,并且使用字符串池缓存,但是我仍然对这个示例感到困惑:

     final String fName = "James";
            String lName = "Gosling";
            String name1 = fName + lName;
            String name2 = fName + "Gosling";
            String name3 = "James" + "Gosling";
           System.out.println(name1 == name2);  // 1
            System.out.println(name2 == name3);
    

    结果是:

    false
    true
    

    我仍然不明白为什么System.out.println(name1==name2);给我一个false,因为我知道这两个值都应该缓存在字符串池中?

    2 回复  |  直到 5 年前
        1
  •  3
  •   JB Nizet    5 年前

    自从 fName 是final,并用一个文本字符串初始化,它是一个常量表达式。

    所以这个指令

    String name2 = fName + "Gosling"
    

    被编译为

    String name2 = "James" + "Gosling"
    

    它被编译成

    String name2 = "JamesGosling"
    

    所以,在字节码中,有相当于

    String name2 = "JamesGosling";
    String name3 = "JamesGosling";
    

    所以name2和name3都引用同一个文本字符串,这个字符串被截取。

    另一方面, lName 不是final,因此不是常量表达式,并且连接发生在运行时而不是编译时。因此,连接创建了一个新的非内联字符串。

        2
  •  1
  •   But I'm Not A Wrapper Class    5 年前

    创建具有相同字符串值的两个字符串并不保证它们都来自字符串池。你需要打电话 s.intern() 以确保从字符串池中获取具有相同值和内存地址的字符串。

    很有可能是串接导致将字符串读取为字符串对象而不是字符串文本。这是因为编译器不知道 fName + lName 是否会导致文字。如果是字符串文字,则转到字符串池。如果它是一个字符串对象,则不能保证它会进入字符串池,并被视为任何其他对象。