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