【问题标题】:Why new keyword not needed for String为什么字符串不需要新关键字
【发布时间】:2024-04-26 03:20:02
【问题描述】:

我是java新手。

在 java 中,Stringclass。但是 我们不必使用new 关键字来创建String 类的对象,而new 用于为其他类创建对象。

我听说过类似 Integer,Double 这样的 Wrapper 类。 但是String 不是 Wrapper,不是吗?

其实我使用的时候发生了什么

     String message = "Hai";

?? 它与

有何不同
String message = new String("Hai");

这里是message 引用变量还是别的什么?? 是否有其他类不需要new 来创建对象??

【问题讨论】:

    标签: java string object new-operator


    【解决方案1】:

    使用以下行,您不是在堆中创建新的 String 对象,而是重用字符串文字(如果已经可用):

    String message = "Hai";
    

    "Hai" 是字符串文字池中的字符串文字。由于字符串是不可变的,因此它们是可重用的,因此它们被 JVM 汇集在字符串文字池中。这是推荐的方式,因为您正在重复使用它。

    但是,您实际上是在创建一个新对象(在堆中):

    String message = new String("Hai");
    

    new String("Hai") 是一个新的String 对象。在这种情况下,即使文字 "Hai" 已经在字符串文字池中,也会创建一个新对象。不建议这样做,因为您可能会以多个具有相同值的 String 对象结尾。

    另请参阅此帖子:Questions about Java's String pool

    还有其他不需要 new 来创建对象的类吗??

    实际上,不使用关键字new,您无法在Java中创建任何对象。

    例如

    Integer i = 1;
    

    并不意味着Integer 对象是在不使用new 的情况下创建的。我们不需要明确地使用new 关键字。但实际上,如果缓存中不存在值为 1 的 Integer 对象(Integer 对象被 JVM 缓存),则将使用 new 关键字来创建它。

    【讨论】:

    • 我认为,Integer 是原始类型int 的包装类。但是字符串不是原始的,不是吗?
    【解决方案2】:

    Java 语言规范允许将字符串表示为文字。您可以将其视为 String 的快捷方式初始化,它具有与通过 new

    进行的常规初始化不同的重要副作用

    字符串字面量都是 interned,这意味着它们是 Java 运行时存储的常量值,可以在多个类之间共享。例如:

    class MainClass (
        public String test = "hello";
    }
    
    class OtherClass {
       public String another = "hello";
    
       public OtherClass() {
           MainClass main = new MainClass();
           System.out.println(main.test == another);
       }
    }
    

    会打印出“true”,因为两个 String 实例实际上都指向同一个对象。如果您通过 new 关键字初始化字符串,则不会出现这种情况。

    【讨论】:

    • +1。简洁明了。如果 OP 想要真正深入研究,我们应该提到 Java 语言规范可在 java.sun.com/docs/books/jls 免费获得。
    【解决方案3】:

    字符串和整数的创建是不同的。

    String s = "Test";
    

    这里 '=' 运算符被重载为字符串。 “一些”+“事物”中的“+”运算符也是如此。 在哪里,

    Integer i = 2;
    

    在 Java 5.0 之前,这是编译时错误;你不能将原语分配给它的包装器。但从 Java 5.0 开始,这被称为自动装箱,其中原语在需要时自动提升到其包装器。

    String h1 = "hi";
    

    将不同于

    String h2 = new String("hi");
    

    原因是 JVM 为所有字符串文字维护了一个字符串表。所以表中会有一个“hi”的条目,说它的地址是1000。

    但是当你显式创建一个字符串对象时,会创建一个新对象,假设它的地址是 2000。现在新对象将指向字符串表中的条目,即 1000。

    所以当你说

    h1 == h2
    

    比较

    1000 == 2000
    

    原来是假的

    【讨论】:

    • = 运算符 NOT 重载。 Java 为字符串提供了一些语法糖,因此当您编写“Hello, World”时,您会获得对代表给定字符流的String 对象的引用。您正在那里隐式创建一个对象(如果需要),但这与 = 运算符没有任何关系。
    【解决方案4】:

    在java中
    "==" 比较左侧和右侧的内存位置(而不是该内存位置的值),因此在

    new String("hai")==new String("hai")

    它返回假。

    在 "Hai"=="Hai" 的情况下,java 不会为相同的字符串文字分配单独的内存,因此这里的 "==" 返回 true。您始终可以使用 equals 方法来比较值。

    【讨论】: