7
        String s1 = new String("string");
        String s2 = new String("string");

        String s3 = "string";
        String s4 = "string";

        System.out.println(s1 == s2);      //FALSE
        System.out.println(s2.equals(s1)); //TRUE

        System.out.println(s3 == s4);      //TRUE
        System.out.println(s3.equals(s4)); //TRUE

s1和 和有什么不一样s3?请告诉我

在 String 中,我们只有 String 对象,那么为什么它会以不同的方式对待这两个对象。s1 和 s2 具有不同的内存地址,而 s3 和 s4 具有相同的内存地址。为什么它基于new运营商工作。?

4

4 回答 4

7

String在您的 Java 源代码中表示字符串文字的对象在String加载定义它们的类时被添加到共享池中1。这确保了字符串文字的所有“副本”实际上都是同一个对象......即使文字出现在多个类中。这就是s3 == s4为什么true

相比之下,当您new使用 String 时,会创建一个不同的新 String 对象。这就是s1 == s2为什么false。(这是 . 的基本属性new。保证创建并返回一个新对象......如果它正常完成。)

但是,在任何一种情况下,字符串都将具有相同的字符,这就是为什么equals返回true.


虽然了解发生了什么很重要,但真正的教训是比较 Java 字符串的正确方法是使用equals而不是==.

如果您想安排您的 String 对象可以使用 进行相等性测试,您可以使用该方法==“实习”它们。String.intern但是,您必须始终如一地这样做......而且实习在各个方面都是一个昂贵的过程......所以这通常不是一个好主意。


1 - 实际上,它比这更复杂一些。它们的对象在类加载和第一次使用文字之间的某个时间被添加到池中。精确的时间是未指定的,并且依赖于 JVM 实现。但是,它保证只发生一次,并且在任何应用程序代码看到String与文字对应的对象引用之前。

于 2013-04-13T09:19:59.783 回答
3

s1是一个新的 String 对象,它不属于任何池化实例的一部分。s3是来自池的字符串的一个实例。查找java 字符串池。看一下相关的intern()方法String

这个概念并不是java独有的。其他语言支持字符串实习。在该相关说明中,池化常用对象遵循元模式,并且不限于字符串。看看Integer.valueOf()。整数也有自己的常量池。

于 2013-04-13T09:19:16.187 回答
2

JVM 具有自动优化功能。除非您专门创建了一个新String对象,并且另一个String对象已经存在具有相同的值,否则会JVM自动假定新对象不是必需的,并将为您分配一个指向String已存在的相等对象的指针。

本质上,当您使用第二个选项时,会发生以下情况:

第1步

创建第一个对象没有问题。

第2步

在创建第二个对象之前,会检查字符串池的值。如果该值当前存在,则无需创建新对象。它只是返回对String对象的引用。

第 3 步

它没有被分配一个新的对象,而是简单地给出了对第 1 步中创建的对象的引用。这是为了节省内存。

于 2013-04-13T09:15:00.610 回答
0

发生这种情况是因为new运算符强制创建 String 的新实例,而在第二种情况下,作为String不可变类,JVM 为两个变量提供相同的 String 实例以节省内存。因为其中一个对象不可能发生变化,从而导致第二个对象也发生变化(不可变,还记得吗?),这没关系。

于 2013-04-13T09:20:24.943 回答