Ответ 1
Вначале следует упомянуть, что StringBuilder
обычно предпочтительнее StringBuffer
. Из StringBuffer
собственный API:
С момента выпуска JDK 5 этот класс был дополнен эквивалентным классом, предназначенным для использования одним потоком,
StringBuilder
. КлассStringBuilder
обычно должен использоваться в предпочтении этому, поскольку он поддерживает все те же операции, но быстрее, поскольку он не выполняет синхронизацию.
Тем не менее, я буду придерживаться 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");
Это включает сдвиги из-за 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"
. A StringBuffer
не имеет встроенной функции. Вы можете попытаться сделать это самостоятельно самым эффективным способом, будь то на месте (возможно, с использованием алгоритма с двумя проходами) или с помощью второго StringBuffer
и т.д.
Но вместо этого я буду использовать replace(CharSequence, CharSequence)
из String
. В большинстве случаев это будет более чем достаточно, и это определенно намного понятнее и проще в обслуживании. Он линейный по длине входной строки, поэтому он асимптотически оптимален.
String before = "str1str2str3";
String after = before.replace("str", "String");
assert after.equals("String1String2String3");
Обсуждение
"Я ищу метод для назначения значения позже, используя предыдущую ячейку памяти"
Точная ячейка памяти не должна быть для вас проблемой; на самом деле, как StringBuilder
, так и StringBuffer
будут перераспределять свой внутренний буфер в разные ячейки памяти, когда это необходимо. Единственный способ предотвратить это будет ensureCapacity
(или установить его через конструктор), чтобы его внутренний буфер всегда был достаточно большим, и его никогда не нужно было перераспределять.
Однако даже если StringBuffer
перераспределяет свой внутренний буфер раз в то время, это не должно быть проблемой в большинстве случаев. Большинство структур данных, которые динамически растут (ArrayList
, HashMap
и т.д.), Делают их таким образом, чтобы сохранить алгоритмически оптимальные операции, используя амортизацию затрат. Я не буду анализировать амортизацию здесь, но если вы не используете системы реального времени и т.д., Это не должно быть проблемой для большинства приложений.
Очевидно, я не знаю специфики вашей потребности, но есть страх перед преждевременной оптимизацией, поскольку вы, кажется, беспокоитесь о вещах, которые у большинства людей есть роскошь, о которых никогда не приходится беспокоиться.