【问题标题】:Java == for String objects ceased to work?Java == for String 对象停止工作?
【发布时间】:2011-03-23 03:52:26
【问题描述】:
  public class Comparison {
        public static void main(String[] args) {
            String s = "prova";
            String s2 = "prova";
            System.out.println(s == s2);
            System.out.println(s.equals(s2));
        }
    }

输出:

true
true

在我的机器上。为什么?不应该是 == 比较对象引用相等吗?

【问题讨论】:

    标签: java


    【解决方案1】:

    因为 String 实例是不可变的,Java 语言能够通过 String 文字(或更一般地说,String 的值是编译时常量)是interned,实际上是指同一个(即==)对象。

    JLS 3.10.5 String Literals

    每个字符串文字都是对class String 实例的引用。 String 对象有一个常量值。字符串字面量——或者更一般地说,作为常量表达式值的字符串——是“内部”的,以便共享唯一的实例,使用方法String.intern

    这就是你得到以下结果的原因:

    System.out.println("yes" == "yes"); // true
    System.out.println(99 + "bottles" == "99bottles"); // true
    System.out.println("7" + "11" == "" + '7' + '1' + (char) (50-1)); // true
    System.out.println("trueLove" == (true + "Love")); // true
    System.out.println("MGD64" == "MGD" + Long.SIZE);
    

    也就是说,你应该依赖==来进行String的比较,而应该使用equals来进行非nullinstanceof String的比较。特别是,不要试图intern() 所有的String,这样你就可以在不知道字符串实习如何工作的情况下使用==

    相关问题


    开启new String(...)

    如果出于某种特殊原因,您需要创建 两个 String 对象(根据定义,它们不是 ==),但又是 equals,那么你可以使用这个构造函数:

    public String(String original):初始化一个新创建的String对象,使其表示与参数相同的字符序列;换句话说,新创建的字符串是参数字符串的副本。 除非需要原始的显式副本,否则无需使用此构造函数,因为Strings 是不可变的

    因此,您可以:

    System.out.println("x" == new String("x")); // false
    

    new 操作符总是创建一个新对象,因此上面保证打印false。也就是说,这通常不是您实际需要做的事情。只要有可能,您应该只使用字符串文字,而不是为其显式创建 new String

    相关问题

    【讨论】:

    • +1 因为所有的答案基本都是一样的,不过这个就麻烦解释一下了。
    • 这是从哪个版本开始实施的?
    • 使用new String(...) 的常见原因是使用子字符串时。如果您的字符串很大,并且您在其上调用 substring(),则返回的子字符串仍将保持对大原始字符串的引用。在某些情况下,这可能会导致问题和内存泄漏——尽管您不再在代码中使用大字符串,但它不会被 GC。要“解决”这个问题,您可以使用new String(largeString.substring(...))。 (我觉得我也应该添加一些有用的评论)。
    • @Peter:是的,这是在链接的问题中(“目的是什么......”)。我正在考虑在此处添加它,但不确定这是否已经太长和/或对初学者来说太混乱了。
    【解决方案2】:

    JLS, 3.10.5 => 保证文字字符串对象将被运行在同一虚拟机中的任何其他代码重用,这些代码恰好包含相同的字符串文字

    【讨论】:

      【解决方案3】:

      如果您显式创建新对象,== 将返回 false:

      String s1 = new String("prova");
      String s2 = new String("prova");
      System.out.println(s1 == s2); // returns false.
      

      否则 JVM 可以使用相同的对象,因此 s1 == s2 将返回 true。

      【讨论】:

        【解决方案4】:

        确实如此。但是字符串字面量是池化的,所以"prova" 返回相同的实例。

        【讨论】:

          【解决方案5】:
          String s = "prova";
          String s2 = "prova";
          

          ss2 是字面量字符串,它们指向 JVM 字符串池中的同一个对象,所以比较返回 true。

          【讨论】:

            【解决方案6】:

            是的,“prova”存储在java内部字符串池中,所以它的引用相同。

            【讨论】:

              【解决方案7】:

              源代码字面量是constant pool 的一部分,所以如果同一个字面量出现多次,在运行时它将是同一个对象。

              【讨论】:

                【解决方案8】:

                JVM 可以优化字符串的使用,以便内存中只有一个“相等”字符串的实例。在这种情况下,== 运算符也将返回 true。不过不要指望它。

                【讨论】:

                  【解决方案9】:

                  您必须了解“==”比较引用,“等于”比较值。 ss1 都指向同一个字符串字面量,所以它们的引用是一样的。

                  【讨论】:

                    【解决方案10】:

                    当您将文字字符串放入 java 代码中时,编译器会自动interned,即创建它的一个静态全局实例。或者更具体地说,它被放入一个实习字符串表中。任何其他引用的字符串在内容方面完全相同,将引用相同的实习字符串。

                    所以在你的代码中 s 和 s2 同一个字符串

                    【讨论】:

                      【解决方案11】:

                      理想情况下它不应该发生。因为java规范保证了这一点。所以我认为这可能是JVM的错误,你应该向sun microsystems报告。

                      【讨论】:

                        猜你喜欢
                        • 2017-07-28
                        • 1970-01-01
                        • 2012-01-24
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2016-12-31
                        • 2019-01-19
                        相关资源
                        最近更新 更多