В чем разница между String и StringBuffer в Java?
В чем разница между String и StringBuffer в Java?
Есть ли максимальный размер для строки?
15 ответов
String
используется для работы со строками символов, которые нельзя изменить (только для чтения и неизменяемые)
StringBuffer
используется для представления символов, которые могут быть изменены.
Производительность мудрая, StringBuffer
быстрее при выполнении конкатенации. Это потому, что когда вы соединяете String
вы создаете новый объект (внутренне) каждый раз с String
неизменен.
Вы также можете использовать StringBuilder
который похож на StringBuffer
кроме этого не синхронизируется. Максимальный размер для любого из них Integer.MAX_VALUE
(231 - 1 = 2 147 483 647) или максимальный размер кучи, деленный на 2 (см. Сколько символов может иметь строка Java?). Больше информации здесь.
String
является неизменным, то есть когда он создан, он никогда не может измениться.
StringBuffer
(или его несинхронизированный родственник StringBuilder
) используется, когда вам нужно построить строку по частям без потери производительности при создании большого количества маленьких String
по пути.
Максимальная длина для обоих - Integer.MAX_VALUE, потому что они хранятся внутри как массивы, а массивы Java имеют только int
для их длины псевдополя.
Улучшение производительности между String
с и StringBuffer
s для множественной конкатенации довольно значительный. Если вы запустите следующий тестовый код, вы увидите разницу. На моем древнем ноутбуке с Java 6 я получаю следующие результаты:
Concat с String занимает: 1781ms Concat с StringBuffer занимает: 0ms
public class Concat
{
public static String concatWithString()
{
String t = "Cat";
for (int i=0; i<10000; i++)
{
t = t + "Dog";
}
return t;
}
public static String concatWithStringBuffer()
{
StringBuffer sb = new StringBuffer("Cat");
for (int i=0; i<10000; i++)
{
sb.append("Dog");
}
return sb.toString();
}
public static void main(String[] args)
{
long start = System.currentTimeMillis();
concatWithString();
System.out.println("Concat with String took: " + (System.currentTimeMillis() - start) + "ms");
start = System.currentTimeMillis();
concatWithStringBuffer();
System.out.println("Concat with StringBuffer took: " + (System.currentTimeMillis() - start) + "ms");
}
}
String StringBuffer
Immutable Mutable
String s=new String("karthik"); StringBuffer sb=new StringBuffer("karthik")
s.concat("reddy"); sb.append("reddy");
System.out.println(s); System.out.println(sb);
O/P:karthik O/P:karthikreddy
--->once we created a String object ---->once we created a StringBuffer object
we can't perform any changes in the existing we can perform any changes in the existing
object.If we are trying to perform any object.It is nothing but mutablity of
changes with those changes a new object of a StrongBuffer object
will be created.It is nothing but Immutability
of a String object
Use String--->If you require immutabilty
Use StringBuffer---->If you require mutable + threadsafety
Use StringBuilder--->If you require mutable + with out threadsafety
String s=new String("karthik");
--->here 2 objects will be created one is heap and the other is in stringconstantpool(scp) and s is always pointing to heap object
String s="karthik";
--->In this case only one object will be created in scp and s is always pointing to that object only
String является неизменным классом. Это означает, что как только вы создадите экземпляр строки, например:
String str1 = "hello";
Объект в памяти не может быть изменен. Вместо этого вам придется создать новый экземпляр, скопировать старую строку и добавить все остальное, как в этом примере:
String str1 = "hello";
str1 = str1 + " world!";
Что действительно происходит, так это то, что мы НЕ обновляем существующий объект str1... мы перераспределяем новую память все вместе, копируем "привет" данные и добавляем "мир"! в конце, затем установите ссылку str1, чтобы указать на эту новую память. Так что под капотом это действительно выглядит так:
String str1 = "hello";
String str2 = str1 + " world!";
str1 = str2;
Отсюда следует, что этот процесс "копирование + вставка и перемещение содержимого в памяти" может быть очень дорогим, если он выполняется повторяющимся образом, особенно рекурсивным.
Когда вам приходится делать что-то снова и снова, используйте StringBuilder. Он является изменяемым и может добавлять строки в конец текущего, потому что он возвращается с помощью [растущего массива] (не 100%, если это фактическая структура данных, может быть списком).
Из API:
Потокобезопасная, изменяемая последовательность символов. Строковый буфер похож на String, но может быть изменен. В любой момент времени он содержит определенную последовательность символов, но длину и содержание этой последовательности можно изменить с помощью определенных вызовов методов.
Я нашел интересный ответ для сравнения производительности String vs StringBuffer Реджи ХатчерсоИсточник: http://www.javaworld.com/javaworld/jw-03-2000/jw-0324-javaperf.html
Java предоставляет классы StringBuffer и String, а класс String используется для управления строками символов, которые нельзя изменить. Проще говоря, объекты типа String доступны только для чтения и неизменны. Класс StringBuffer используется для представления символов, которые могут быть изменены.
Существенное различие в производительности между этими двумя классами заключается в том, что StringBuffer быстрее, чем String, при выполнении простых конкатенаций. В коде манипуляции со строками строки символов обычно объединяются. Используя класс String, конкатенации обычно выполняются следующим образом:
String str = new String ("Stanford ");
str += "Lost!!";
Если бы вы использовали StringBuffer для выполнения той же конкатенации, вам понадобился бы код, который выглядит следующим образом:
StringBuffer str = new StringBuffer ("Stanford ");
str.append("Lost!!");
Разработчики обычно предполагают, что первый пример выше более эффективен, потому что они думают, что второй пример, который использует метод добавления для конкатенации, является более дорогостоящим, чем первый пример, который использует оператор + для объединения двух объектов String.
Оператор + выглядит невинным, но сгенерированный код вызывает некоторые сюрпризы. Использование StringBuffer для конкатенации может фактически создать код, который значительно быстрее, чем использование String. Чтобы выяснить, почему это так, мы должны изучить сгенерированный байт-код из наших двух примеров. Байт-код для примера с использованием String выглядит следующим образом:
0 new #7 <Class java.lang.String>
3 dup
4 ldc #2 <String "Stanford ">
6 invokespecial #12 <Method java.lang.String(java.lang.String)>
9 astore_1
10 new #8 <Class java.lang.StringBuffer>
13 dup
14 aload_1
15 invokestatic #23 <Method java.lang.String valueOf(java.lang.Object)>
18 invokespecial #13 <Method java.lang.StringBuffer(java.lang.String)>
21 ldc #1 <String "Lost!!">
23 invokevirtual #15 <Method java.lang.StringBuffer append(java.lang.String)>
26 invokevirtual #22 <Method java.lang.String toString()>
29 astore_1
Байт-код в позициях от 0 до 9 выполняется для первой строки кода, а именно:
String str = new String("Stanford ");
Затем выполняется байт-код в местоположении с 10 по 29 для объединения:
str += "Lost!!";
Вещи становятся интересными здесь. Байт-код, сгенерированный для конкатенации, создает объект StringBuffer, затем вызывает его метод добавления: временный объект StringBuffer создается в местоположении 10, а его метод добавления вызывается в местоположении 23. Поскольку класс String является неизменным, необходимо использовать StringBuffer для конкатенации.
После выполнения конкатенации объекта StringBuffer его необходимо преобразовать обратно в строку. Это делается с помощью вызова метода toString в местоположении 26. Этот метод создает новый объект String из временного объекта StringBuffer. Создание этого временного объекта StringBuffer и его последующее преобразование обратно в объект String очень дороги.
Таким образом, две строки кода выше приводят к созданию трех объектов:
- Объект String в местоположении 0
- Объект StringBuffer в местоположении 10
- Объект String в местоположении 26
Теперь давайте посмотрим на байт-код, сгенерированный для примера с использованием StringBuffer:
0 new #8 <Class java.lang.StringBuffer>
3 dup
4 ldc #2 <String "Stanford ">
6 invokespecial #13 <Method java.lang.StringBuffer(java.lang.String)>
9 astore_1
10 aload_1
11 ldc #1 <String "Lost!!">
13 invokevirtual #15 <Method java.lang.StringBuffer append(java.lang.String)>
16 pop
Байт-код в позициях от 0 до 9 выполняется для первой строки кода:
StringBuffer str = new StringBuffer("Stanford ");
Байт-код в местоположении с 10 по 16 затем выполняется для объединения:
str.append("Lost!!");
Обратите внимание, что, как и в первом примере, этот код вызывает метод append объекта StringBuffer. Однако, в отличие от первого примера, нет необходимости создавать временный StringBuffer и затем преобразовывать его в объект String. Этот код создает только один объект, StringBuffer, в местоположении 0.
В заключение, конкатенация StringBuffer значительно быстрее, чем конкатенация String. Очевидно, что StringBuffers следует использовать в этом типе операций, когда это возможно. Если требуется функциональность класса String, рассмотрите возможность использования StringBuffer для объединения, а затем выполните одно преобразование в String.
StringBuffer используется для создания одной строки из множества строк, например, когда вы хотите добавить части строки в цикл.
Вы должны использовать StringBuilder вместо StringBuffer, когда у вас есть только один поток, обращающийся к StringBuffer, поскольку StringBuilder не синхронизируется и, следовательно, быстрее.
AFAIK, в Java как языке нет верхнего предела размера строки, но JVM, вероятно, имеют верхний предел.
Путем печати хеш-кода объекта String/StringBuffer после того, как любая операция добавления также докажет, объект String каждый раз воссоздается внутри с новыми значениями, а не с использованием одного и того же объекта String.
public class MutableImmutable {
/**
* @param args
*/
public static void main(String[] args) {
System.out.println("String is immutable");
String s = "test";
System.out.println(s+"::"+s.hashCode());
for (int i = 0; i < 10; i++) {
s += "tre";
System.out.println(s+"::"+s.hashCode());
}
System.out.println("String Buffer is mutable");
StringBuffer strBuf = new StringBuffer("test");
System.out.println(strBuf+"::"+strBuf.hashCode());
for (int i = 0; i < 10; i++) {
strBuf.append("tre");
System.out.println(strBuf+"::"+strBuf.hashCode());
}
}
}
Вывод: выводит значение объекта вместе со своим хеш-кодом
String is immutable
test::3556498
testtre::-1422435371
testtretre::-1624680014
testtretretre::-855723339
testtretretretre::2071992018
testtretretretretre::-555654763
testtretretretretretre::-706970638
testtretretretretretretre::1157458037
testtretretretretretretretre::1835043090
testtretretretretretretretretre::1425065813
testtretretretretretretretretretre::-1615970766
String Buffer is mutable
test::28117098
testtre::28117098
testtretre::28117098
testtretretre::28117098
testtretretretre::28117098
testtretretretretre::28117098
testtretretretretretre::28117098
testtretretretretretretre::28117098
testtretretretretretretretre::28117098
testtretretretretretretretretre::28117098
testtretretretretretretretretretre::28117098
String
является неизменным массивом символов
StringBuffer
изменяемый массив символов Часто преобразуется обратно в String
когда закончишь мутировать.
Поскольку оба являются массивом, максимальный размер для обоих равен максимальному размеру целого числа, которое равно 2^31-1 (см. JavaDoc, также проверьте JavaDoc для обоих String
а также StringBuffer
). Это потому что .length
аргумент массива является примитивным int
, (См. Массивы).
StringBuffer
или его младший и более быстрый брат StringBuilder
предпочтительнее, когда вы собираетесь делать много конкатенаций строк во вкусе
string += newString;
или эквивалентно
string = string + newString;
потому что вышеупомянутые конструкции неявно создают новую строку каждый раз, что будет огромной производительностью и падением. StringBuffer
/ StringBuilder
находится под капотом лучше всего сравнивать с динамически расширяемым List<Character>
,
Хотя я понимаю, что это не является основным отличительным фактором, сегодня я заметил, что StringBuffer(и StringBuilder) предоставляет некоторые интересные методы, которых нет в String.
- задний ход()
- setCharAt ()
Различия
- Только в классе String оператор + перегружен. Мы можем объединить два объекта String с помощью оператора +, но в случае StringBuffer мы не можем.
КлассString переопределяет toString(), equals(), hashCode() класса Object, но StringBuffer переопределяет только toString().
String s1 = new String("abc"); String s2 = new String("abc"); System.out.println(s1.equals(s2)); // output true StringBuffer sb1 = new StringBuffer("abc"); StringBuffer sb2 = new StringBuffer("abc"); System.out.println(sb1.equals(sb2)); // output false
КлассString может быть как Serializable, так и Comparable, но StringBuffer может быть только Serializable.
Set<StringBuffer> set = new TreeSet<StringBuffer>(); set.add(sb1); set.add(sb2); System.out.println(set); // gives ClassCastException because there is no Comparison mechanism
Мы можем создать объект String с оператором new и без него, но объект StringBuffer можно создать только с помощью оператора new.
- String неизменен, но StringBuffer изменчив.
- StringBuffer синхронизируется, а String - нет.
- StringBuffer имеет встроенный метод reverse(), но у String его нет.
Строка является неизменной, это означает, что когда вы выполняете операцию над строкой, вы действительно создаете совершенно новую строку.
StringBuffer является изменяемым, и вы можете добавить к нему, а также сбросить его длину до 0.
На практике компилятор, по-видимому, использует StringBuffer во время конкатенации строк для повышения производительности.
Мудрый по производительности StringBuffer намного лучше, чем String; потому что всякий раз, когда вы применяете конкатенацию к объекту String, новый объект String создается при каждой конкатенации.
Основное правило: String являются неизменяемыми (не модифицируемые), а StringBuffer являются изменяемыми (модифицируемые)
Вот программный эксперимент, где вы получите разницу в производительности
public class Test {
public static int LOOP_ITERATION= 100000;
public static void stringTest(){
long startTime = System.currentTimeMillis();
String string = "This";
for(int i=0;i<LOOP_ITERATION;i++){
string = string+"Yasir";
}
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
}
public static void stringBufferTest(){
long startTime = System.currentTimeMillis();
StringBuffer stringBuffer = new StringBuffer("This");
for(int i=0;i<LOOP_ITERATION;i++){
stringBuffer.append("Yasir");
}
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
}
public static void main(String []args){
stringTest()
stringBufferTest();
}
}
Вывод строки в моей машине 14800
Вывод StringBuffer в моей машине 14