16

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

StringBuffer sb=new StringBuffer("teststr");

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

4

8 回答 8

28
sb.setLength(0);
sb.append("testString");
于 2010-04-07T17:35:49.120 回答
17

首先应该提到的StringBuilder是一般首选StringBuffer。来自StringBuffer自己的 API

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

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


问题

StringBuffer sb = new StringBuffer("teststr");

“现在我必须在不清空内容的情况下更改sbto的值”"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");

这涉及由于deleteCharAt和的变化insert

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");

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

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

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

讨论

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

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

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

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

于 2010-04-12T05:29:07.373 回答
8

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

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

通常,通过查看相关类的 API 文档可以轻松回答此类问题。

于 2010-04-07T11:14:03.643 回答
3

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

编辑您可以使用该功能
覆盖一系列元素。replace()要将整个值更改为newval,您可以使用buffer.replace(0,buffer.length(),newval)。也可以看看:

于 2010-04-07T11:15:10.917 回答
2

您可能正在寻找 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");
于 2010-04-07T11:41:03.913 回答
1

确实,我认为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;
  }
于 2010-04-15T12:54:06.943 回答
1

更改 StringBuffer 的整个值:

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

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

于 2016-02-04T02:26:53.440 回答
0

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

 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
于 2010-04-07T11:15:03.723 回答