В чем разница между String и StringBuffer в Java? - PullRequest
63 голосов
/ 13 марта 2010

В чем разница между String и StringBuffer в Java?

Есть ли максимальный размер для строки?

Ответы [ 15 ]

75 голосов
/ 13 марта 2010

String используется для управления строками символов, которые нельзя изменить (только для чтения и неизменяемые).

StringBuffer используется для обозначения символов, которые могут быть изменены.

По производительности, StringBuffer быстрее при выполнении конкатенации. Это потому, что когда вы объединяете String, вы создаете новый объект (внутри) каждый раз, когда String является неизменным.

Вы также можете использовать StringBuilder, что аналогично StringBuffer, за исключением того, что оно не синхронизировано. Максимальный размер любого из них составляет Integer.MAX_VALUE (2 31 - 1 = 2 147 483 647) или максимальный размер кучи, деленный на 2 (см. Сколько символов может иметь строка Java? ) , Больше информации здесь .

34 голосов
/ 13 марта 2010

A String является неизменным, то есть когда оно создается, оно никогда не может измениться.

A StringBuffer (или его несинхронизированный двоюродный брат StringBuilder) используется, когда вам нужно составить строку по частям без лишних затрат на создание множества маленьких String s по пути.

Максимальная длина для обоих - Integer.MAX_VALUE, потому что они хранятся внутри как массивы, а для массивов Java только псевдополя длины int.

Улучшение производительности между String с и StringBuffer с для множественной конкатенации весьма значительно. Если вы запустите следующий тестовый код, вы увидите разницу. На моем древнем ноутбуке с Java 6 я получаю следующие результаты:

Concat with String took: 1781ms
Concat with StringBuffer took: 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");
    }
}
23 голосов
/ 22 марта 2013
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
10 голосов
/ 04 марта 2011

String является неизменным классом. Это означает, что как только вы создадите экземпляр строки, например:

String str1 = "hello";

Объект в памяти не может быть изменен. Вместо этого вам придется создать новый экземпляр, скопировать старую строку и добавить все остальное, как в этом примере:

String str1 = "hello";
str1 = str1 + " world!";

Что на самом деле происходит, так это то, что мы НЕ обновляем существующий объект str1 ... мы перераспределяем новую память вместе, копируем данные "привет" и добавляем "мир!" в конце, затем установите ссылку str1, чтобы указать на эту новую память. Так что под капотом это действительно выглядит так:

String str1 = "hello";
String str2 = str1 + " world!";
str1 = str2;

Таким образом, из этого следует, что этот процесс «копирование + вставка и перемещение содержимого в памяти» может быть очень дорогим, если он выполняется с повторением, особенно рекурсивно.

Когда вы находитесь в такой ситуации, когда вам приходится делать что-то снова и снова, используйте StringBuilder. Он изменчив и может добавлять строки в конец текущего, потому что он возвращается с помощью [растущего массива] (не на 100%, если это фактическая структура данных, может быть списком).

4 голосов
/ 04 марта 2011

Из API:

Потокобезопасная, изменяемая последовательность символов. Строковый буфер похож на String, но может быть изменен. В любой момент времени он содержит определенную последовательность символов, но длину и содержание этой последовательности можно изменить с помощью определенных вызовов методов.

2 голосов
/ 23 июня 2016

Путем печати хэш-кода объекта 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
2 голосов
/ 23 ноября 2010

Я нашел интересный ответ для сравнения производительности 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 очень дороги.

В итоге, две строки кода выше приводят к созданию трех объектов:

  1. Объект String в местоположении 0
  2. Объект StringBuffer в местоположении 10
  3. Объект 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.

2 голосов
/ 13 марта 2010

StringBuffer используется для создания одной строки из множества строк, например, когда вы хотите добавить части строки в цикл.

Вы должны использовать StringBuilder вместо StringBuffer, когда у вас есть только один поток, обращающийся к StringBuffer, поскольку StringBuilder не синхронизируется и, следовательно, быстрее.

AFAIK, в Java как языке нет верхнего предела для размера строки, но JVM, вероятно, имеют верхний предел.

1 голос
/ 17 января 2017

Различия

  1. Только в Строка класс + оператор перегружен. Мы можем объединить два объекта String, используя оператор + , но в случае StringBuffer мы не можем.
  2. String класс переопределяет toString (), равно (), 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
    
  3. String класс имеет как Сериализуемый , так и Сравнимый , но StringBuffer только Сериализуемый .

    Set<StringBuffer> set = new TreeSet<StringBuffer>();
    set.add(sb1);
    set.add(sb2);
    System.out.println(set);  // gives ClassCastException because there is no Comparison mechanism
    
  4. Мы можем создать объект String с оператором new и без него, но объект StringBuffer можно создать только с использованием оператора new .

  5. String неизменяемый, но StringBuffer изменяемый.
  6. StringBuffer синхронизируется, а String - нет.
  7. StringBuffer имеет встроенный метод reverse () , но у String его нет.
1 голос
/ 20 ноября 2014

Хотя я понимаю, что это не является основным отличительным фактором, сегодня я заметил, что StringBuffer (и StringBuilder) предоставляет некоторые интересные методы, которых нет в String.

  • обратный ()
  • setCharAt ()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...