为啥字符串不需要新关键字

Posted

技术标签:

【中文标题】为啥字符串不需要新关键字【英文标题】:Why new keyword not needed for String为什么字符串不需要新关键字 【发布时间】:2012-01-30 14:36:02 【问题描述】:

我是java新手。

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

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

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

     String message = "Hai";

?? 它与

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

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

【问题讨论】:

【参考方案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 方法来比较值。

【讨论】:

以上是关于为啥字符串不需要新关键字的主要内容,如果未能解决你的问题,请参考以下文章

为啥指针不继承字符串文字的固定大小

字符串是 Java 中的对象,那么我们为啥不使用 'new' 来创建它们呢?

为啥关键字参数必须作为带有符号键的哈希传递,而不是 Ruby 中的字符串键?

ES6的新特性

为啥不能为 Java 中的 var 关键字分配 lambda 表达式?

为啥新的 Visual Studio 将字符串文字作为指向常量的指针?