【问题标题】:Difference between String and StringBuilder and their internal organizationString 和 StringBuilder 之间的区别及其内部组织
【发布时间】:2011-11-08 02:51:32
【问题描述】:

这是一个非常基本的问题。我知道的答案范围是字符串是不可变的。字符串生成器不是,因此您可以在末尾附加字符。

那么字符串构建器是如何内部组织的? String 是一个字符数组。

StringBuilder 也是一个字符数组吗? 所以,我有一个 StringBuilder MY_OBJ="Hello"。 现在,如果我尝试将字符附加到 MY_OBJ 的末尾,这是否意味着您实际上是在创建一个新的数组对象并将所有这些字符复制到一个新的对象中?如果是这样,它如何比字符串更有效?

我想到的另一个问题是,如何标记 StringBuilder 的结束? 就像在 C 中一样,我们使用“/0”

【问题讨论】:

    标签: java string stringbuilder


    【解决方案1】:

    大部分 StringBuilder 实现来自AbstractStringBuilder,在 Sun 的实现中,它是一个 char 数组的包装器。没有标记字符串的结尾,该类本身包含一个计数变量,表示字符串的实际大小。还有一个 capacity 方法会告诉你真正的数组有多大(还有一个 trimToSize 方法将字符串生成器修剪成一个与当前存储的字符串一样大的数组)。

    仅当您达到当前字符串生成器容量时才会创建新数组,并且此操作并不昂贵,因为它使用 arrayCopy 方法并且容量总是加倍,因此随着您的增长,您达到限制。如果您事先知道您认为字符串构建器的大小,您还可以在它的构造函数上定义,这样它就不必将内容复制到新数组中。

    另外,这段代码:

    StringBuilder MY_OBJ= "Hello";
    

    不起作用。

    但是这个可以:

    StringBuilder MY_OBJ= new StringBuilder("Hello");
    

    【讨论】:

    • 谢谢,我的疑惑得到了澄清:)。
    • Nitpick - 在某些情况下容量会增加一倍以上,而在其他情况下则不到一倍。 (看代码。)但是,这些情况是例外,所以你基本上是对的。
    • 现在确定负的 newCapacity 是如何发生的,因为所有方法都针对负值进行验证,并且 StringBuilder 构造函数 javadoc 表示如果提供负值,它将抛出异常。
    【解决方案2】:

    我不知道。我们去看看:

    72   public final class StringBuilder
    73       extends AbstractStringBuilder
    
    45        * The value is used for character storage.
    46        */
    47       char[] value;
    48   
    49       /**
    50        * The count is the number of characters used.
    51        */
    52       int count;
    

    ===

    StringBuilder 也是一个字符数组吗?

    显然,在这个特定的实现中。

    所以,我有一个 StringBuilder MY_OBJ="Hello"。现在,如果我尝试将字符附加到 MY_OBJ 的末尾,这是否意味着您实际上是在创建一个新的数组对象并将所有这些字符复制到一个新的对象中?

    不一定。数组不一定是满的 (count < value.length),因此可能不需要分配新数组。理想情况下,您将 StringBuilder 初始化为一个容量,以便从一开始就分配足够大的数组。

    StringBuilder sb = new StringBuilder(20);
    sb.append("Hello");
    ...
    sb.append(" there");
    

    我想到的另一个问题是,如何标记 StringBuilder 的结束?就像在 C 中一样,我们使用“/0”

    你不在乎 - String/StringBuilder 会在内部处理它。

    【讨论】:

    • +1 指出来源可供任何人自行寻找。
    • 如果StringBuilder 的内部数组的计数大于实际字符串长度,则意味着StringBuilder 是动态数组而String 因为它不可变(固定大小)是普通数组?
    【解决方案3】:

    如果您不打算更改值,StringBuilder 并不比 String 更有效。如果您想在字符串中追加/删除字符,效率会更高。

    StringBuilder 的默认构造函数将创建一个可以容纳 16 个 char 元素的数组。 #append(String) 使用String#getChars(int, int, char[], int) 将字符串的字符复制到StringBuidler 的数组中。仅当没有空间添加更多字符时,才使用Arrays.copyOf(char[], int) 重新调整数组的大小。每次发生这种情况时,阵列的容量都会增加一倍。通过计算数组中有多少个字符来标记结尾。

    在旧版本的 Java 中,当您在循环中连接字符串时,每个字符串与 + 运算符的连接都会创建一个新的 String 对象。 StringBuilder 更快,因为它创建的对象更少。

    如果您要保留 StringBuilder 实例,您可能需要在完成修改后调用StringBuilder#trimToSize()。它将尝试将数组的容量减少到所需的最小值。

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 2023-03-10
      • 1970-01-01
      • 2015-07-05
      • 1970-01-01
      • 2012-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多