【问题标题】:String empty constructor in java [closed]java中的字符串空构造函数[关闭]
【发布时间】:2012-09-07 22:46:19
【问题描述】:

我正在研究 String API,突然发现一个 String 空构造函数,即我们可以使用 String s = new String() 构造一个空 String 对象

不知道有没有用呢?

【问题讨论】:

  • 有趣的问题。 String() 的 Javadocs 声明“请注意,没有必要使用此构造函数,因为字符串是不可变的。”
  • 我认为如果你使用未初始化的对象 java 给你空指针 exeption.. 并且这样的 s 包含空字符串
  • 仅用于 init ` 初始化一个新创建的 String 对象,使其表示一个空字符序列。`
  • 这是一个很好的问题,关于主题,不应该被删除。该构造函数的存在确实看起来很奇怪,人们可能想知道这是否是库设计者的错误,可能只是为了向后兼容而保留,或者它是否有一个微妙的用例。

标签: java string


【解决方案1】:

当然.....

String s = new String();

将在堆上创建一个非文字字符串对象,该对象被垃圾回收。

在哪里

String s = "" ;

将创建一个字符串文字。如果可以通过默认加载​​器访问此将不会进行垃圾收集。

请参阅下面的此链接,了解我提出的问题。这可能与您的问题没有直接关系,但它肯定会帮助您牢牢掌握这个概念。

Is String Literal Pool a collection of references to the String Object, Or a collection of Objects

【讨论】:

  • 字符串文字可以被 GC-ed。一些常见的可能在整个 jvm 生命周期中都被强烈引用。
  • 我听说从 Ja​​va 7 开始可以对实习字符串进行 GC。
  • 我很难想象这样一个场景:空字符串的实例是否可以被垃圾回收。
  • "" 进入字符串常量(字面量)池,而 new String () 进入堆。
  • “这永远不会被垃圾收集” - 非常不正确。
【解决方案2】:

先了解一些背景

因为 Java 中的字符串是不可变的,所以它们也是“内部的”——这意味着加载的类中的所有 字符串文字 都保存在一个池中,因此每个类通常只有一个实例一次在内存中唯一的字符串文字。它是 flyweight 模式的应用,类似的池也用于 Integer 和其他原始包装对象(但仅限于有限数量的小值)。

由于这种机制,通常可以对字符串文字(甚至来自不同类)进行身份比较(尽管在比较字符串时应始终使用equals 方法以确保安全性和一致性):

System.out.println("hello" == "hello"); // true

现在,如果您使用默认的字符串构造函数,您将获得一个空字符串的实例,但它是一个 new 实例,如 JavaDoc 中所述:

初始化一个新创建的 String 对象,使其代表一个空字符序列。请注意,由于字符串是不可变的,因此不需要使用此构造函数。

这样的新实例与被实习的空字符串不同,导致:

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

但正如我所说,只有 字符串字面量 会自动被实习 - 这意味着由 StringBuilders 手动创建的字符串、来自 char 数组等的字符串不会被实习。您可以使用String.intern() 方法手动将这样的字符串放入池中。

现在来看一些真实的场景

这一切确实很好,但我还没有回答为什么这个构造函数存在。嗯,Java 字符串只是 char 数组 的智能包装器,一些不同的字符串对象可以共享它们的内部数组。

如果我创建了一个很长的字符串(例如通过从流中读取),那么这个实例不会被实习(如上所述),因此在引用它的变量超出范围后它将被垃圾收集。但如果这样做:

String longString = readVeryLongString();
String shortString = longString.subString(0, 10);

... 那么新的shortString 不会从longString 复制前10 个字符并将它们放入自己的新字符数组中。不,它将引用原始数组,仅使用其中的前 10 个字符。

现在,如果 shortString 变量的生命周期更长(例如放入某个静态上下文中),那么底层 char 数组不会被垃圾回收(即使原来的 longString 变量已经超出范围)。 这是在 Java 中创建内存泄漏的方法之一。

现在,默认的字符串构造函数来拯救了!如果我把上面的代码改成这样:

String longString = readVeryLongString();
String shortString = new String(longString.subString(0, 10));

...那么shortString 将是一个新的字符串实例,它通过从subString 方法返回的原始字符串中仅复制所需的 10 个字符来创建一个新的内部字符数组。


一篇很好的文章说明了这个主题:

http://illya-keeplearning.blogspot.cz/2009/03/java-string-internals.html

【讨论】:

  • 这很好地解释了new String(existingString) 的用途,但问题实际上是关于new String() 没有参数。 :-/
  • 是的,你说得对,我有点得意忘形了。 :) 我会尝试更新答案...
【解决方案3】:

它创建了一个空字符串,它似乎有一些有限的用途。

如果您要通过连接来构建String,并且不使用例如StringBuiler,您的代码可以以下列之一开头。

String result = new String();
String result = "";
String result = "first part of string";

// ...
result += "append to the result";

前两个等效,您应该更喜欢使用"" 进行初始化,因为这可以利用string interning

【讨论】:

  • 如果您可以使用文字“”,则无需致电new String()。这两个不是等价的,因为构造函数创建了一个新实例,但是 "" 字面量使用了运行时池中的实例。
  • @Natix 已编辑,我的回答确实 suggest 两者是等价的。
【解决方案4】:

小例子...字符串可以被垃圾回收

System.out.println(1 + new String() + 2);

而不是

System.out.println(1 + "" + 2);

【讨论】:

    【解决方案5】:

    根据文档,此构造函数创建一个空序列。

    public String()
    
    Initializes a newly created String object so that it represents an empty character sequence. Note that use of this constructor is unnecessary since Strings are immutable.
    

    如果你想要一个空序列,这是有道理的。

    但通常情况下,在更改它之前没有必要使用空构造函数,因为您没有更改字符串。实际上,例如,当您使用运算符 += 进行更改时,您正在创建另一个不可变字符串,而不是更改一个。

    检查有关此主题的问题:How do String objects work (like immutable objects)?

    【讨论】:

      【解决方案6】:

      要创建一个空字符串,调用默认构造函数为 String s new String();

      将创建一个没有字符的 String 实例。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-05-06
        • 1970-01-01
        • 2017-08-05
        • 2020-06-04
        • 2013-08-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多