如何重新分配 StringBuffer 的值?

Posted

技术标签:

【中文标题】如何重新分配 StringBuffer 的值?【英文标题】:How to Reassign value of StringBuffer? 【发布时间】:2011-02-05 05:15:30 【问题描述】:

我们如何重新分配 StringBuffer 或 StringBuilder 变量的值?

StringBuffer sb=new StringBuffer("teststr");

现在我必须在不清空内容的情况下将 sb 的值更改为“testString”。 我正在研究一种无需使用单独的内存分配即可直接执行此分配的方法。我认为我们只能在清空内容后才能执行此操作。

【问题讨论】:

您能否详细说明您想要实现的目标是什么?尤其是StringBuffer,你不会接受更新、更快、更好的StringBuilder吗? 在 Java 中,assignment 运算符是 =,而 reassignment 术语通常应用于范围变量(例如 sb = new StringBuffer())。所以,一般来说,你的问题有点不正确,因为你能得到的唯一答案是sb = new StringBuffer("testString")——你可能不会问关于这类事情的丰富问题。而“不清空内容”这句话带来了完全的混乱。所以请花点时间更好地解释你的目标。 @polygenelubricants StringBuilder 没问题。但是我正在寻找 StringBuilder 中的方法,以便稍后使用以前的方法分配值。内存位置。 @cdb:请参阅我的回答中的讨论部分。 @cdb,请进一步解释您在使用 replace() 时遇到的问题。 【参考方案1】:

“重新分配”是什么意思?您可以使用 setLength() 清空内容,然后开始添加新内容,如果您是这个意思的话。

编辑:要更改部分内容,您可以使用replace()

一般来说,这类问题可以通过查看相关类的 API 文档轻松回答。

【讨论】:

另外,我很确定replace() 会将新字符串复制到 StringBuilder 存储中。我认为你不能在没有内存分配的情况下做到这一点。 @sblom:如果 StringBuilder 的底层数组足够长以容纳替换的字符串,则不需要进行任何分配。【参考方案2】:

您可以转换为字符串,如下所示:

 StringBuffer buf = new StringBuffer();
 buf.append("s1");
 buf.append("s2");

 StringBuilder sb = new StringBuilder(buf.toString());
 // Now sb, contains "s1s2" and you can further append to it

【讨论】:

【参考方案3】:

您可以使用StringBuilder 代替StringBuffer,如果可以的话,这通常是人们所做的(StringBuilder 不同步,因此它更快但不是线程安全的)。如果需要初始化其中一个的内容,请使用toString() 方法获取字符串表示。要回收现有的StringBuilderStringBuffer,只需致电setLength(0)

编辑 您可以使用replace() 函数覆盖一系列元素。要将整个值更改为newval,您可以使用buffer.replace(0,buffer.length(),newval)。另见:

StringBuilder StringBuffer

【讨论】:

【参考方案4】:

您可能正在寻找 StringBuffer 的 replace() 方法:

StringBuffer sb=new StringBuffer("teststr");
sb.replace(0, sb.length() - 1, "newstr");

在内部,它会删除原始字符串,然后插入新字符串,但它可能会为您节省一步:

StringBuffer sb=new StringBuffer("teststr");
sb.delete(0, sb.length() - 1);
sb.append("newstr");

使用 setLength(0) 将零长度 StringBuffer 重新分配给变量,我猜这不是您想要的:

StringBuffer sb=new StringBuffer("teststr");
// Reassign sb to a new, empty StringBuffer
sb.setLength(0);
sb.append("newstr");

【讨论】:

它不会删除原始字符串!检查我的答案!【参考方案5】:
sb.setLength(0);
sb.append("testString");

【讨论】:

@GreenieMeanie,啊哈,我真的很喜欢你的评论。正是我的想法)【参考方案6】:

首先应该提到的是,StringBuilder 通常比StringBuffer 更受欢迎。来自StringBuffer's own API:

从 JDK 5 版本开始,该类已经补充了一个为单线程使用而设计的等效类 StringBuilderStringBuilder 类通常应该优先于这个类,因为它支持所有相同的操作,但速度更快,因为它不执行同步。

也就是说,我会坚持StringBuffer 来回答其余的问题,因为这就是你要问的; StringBuffer 所做的一切,StringBuilder 也...除了同步,这通常是不需要的。因此,除非您在多个线程中使用缓冲区,否则切换到 StringBuilder 是一项简单的任务。


问题

StringBuffer sb = new StringBuffer("teststr");

“现在我必须将sb 的值更改为"testString" 而不清空内容”

所以您希望sb 在其缓冲区中有String"testString"?有很多方法可以做到这一点,我将列出其中的一些来说明如何使用 API。


最佳解决方案:它执行从"teststr""testString" 的最小编辑。不可能比这更快。

StringBuffer sb = new StringBuffer("teststr");
sb.setCharAt(4, 'S');
sb.append("ing");
assert sb.toString().equals("testString");

这会不必要地用"tr" 覆盖"tr"

StringBuffer sb = new StringBuffer("teststr");
sb.replace(4, sb.length(), "String");
assert sb.toString().equals("testString");

这涉及由于deleteCharAtinsert 而导致的班次。

StringBuffer sb = new StringBuffer("teststr");
sb.deleteCharAt(4);
sb.insert(4, 'S');
sb.append("ing");
assert sb.toString().equals("testString");

现在有点不同:它不会神奇地知道它有 "teststr" 需要编辑为 "testString";它仅假设StringBuffer 在某处至少包含一次"str",并且需要将其替换为"String"

StringBuffer sb = new StringBuffer("strtest");
int idx = sb.indexOf("str");
sb.replace(idx, idx + 3, "String");
assert sb.toString().equals("Stringtest");

现在假设您要替换 ALL 次出现的 "str" 并将其替换为 "String"StringBuffer 没有内置此功能。您可以尝试以最有效的方式自己完成,无论是就地(可能使用 2-pass 算法)或使用第二个 StringBuffer 等。

但我将使用来自Stringreplace(CharSequence, CharSequence)。在大多数情况下,这已经绰绰有余,而且绝对更清晰,更容易维护。它在输入字符串的长度上是线性的,所以它是渐近最优的。

String before = "str1str2str3";
String after = before.replace("str", "String");
assert after.equals("String1String2String3");

讨论

“我正在寻找稍后使用以前的内存位置分配值的方法”

确切的内存位置不应该是您真正关心的问题;事实上,StringBuilderStringBuffer 都会在必要时将其内部缓冲区重新分配到不同的内存位置。防止这种情况发生的唯一方法是ensureCapacity(或通过构造函数设置),以便其内部缓冲区始终足够大,并且永远不需要重新分配。

但是,即使StringBuffer 确实偶尔重新分配其内部缓冲区,在大多数情况下也不应该成为问题。大多数动态增长的数据结构(ArrayListHashMap 等)都以保留算法最优操作的方式执行它们,并利用成本摊销。我不会在这里进行摊销分析,但除非您正在做实时系统等,否则对于大多数应用程序来说这应该不是问题。

显然,我不了解您的具体需求,但担心过早优化,因为您似乎在担心大多数人不必担心的事情。

【讨论】:

是的,知道这是一种过早的优化,但我问这个是因为这是面试中的热门话题。 "确切的内存位置不应该是您真正关心的问题;" -- 是的,但如果方法采用参数void func(StringBuilder sb),您可能需要清除那个确切的参数。 sb.setLength(0); 会在这里做,但sb = new StringBuilder(); 不会——当然。 "确切的内存位置不应该是你真正关心的问题":好吧,如果我像这样重新分配 StringBuilder 变量:sb = new StringBuilder(newValue); 那么我将无法通过这个lambda 函数中的变量,因为“变量必须是最终的或有效的最终”。【参考方案7】:

确实,我认为replace() 是最好的方法。我检查了 Java 源代码。它确实覆盖了旧字符。

这里是replace()的源代码:

public AbstractStringBuffer replace(int start, int end, String str)
  
    if (start < 0 || start > count || start > end)
      throw new StringIndexOutOfBoundsException(start);

    int len = str.count;
    // Calculate the difference in 'count' after the replace.
    int delta = len - (end > count ? count : end) + start;
    ensureCapacity_unsynchronized(count + delta);

    if (delta != 0 && end < count)
      VMSystem.arraycopy(value, end, value, end + delta, count - end);

    str.getChars(0, len, value, start);
    count += delta;
    return this;
  

【讨论】:

【参考方案8】:

更改 StringBuffer 的整个值:

  StringBuffer sb = new StringBuffer("word");
  sb.setLength(0); // setting its length to 0 for making the object empty
  sb.append("text");

这就是您可以更改 StringBuffer 的整个值的方法。

【讨论】:

以上是关于如何重新分配 StringBuffer 的值?的主要内容,如果未能解决你的问题,请参考以下文章

String和StringBuffer的区别

java 问题:String类和 Bufstring类的区别是啥?谢谢

Java基础知识

String与StringBuffer,StringBuilder

String和StringBuffer

Java StringBuffer与StringBuider