Я считаю, что все хорошо понимают разницу между String и StringBuffer, но, по оценкам, есть еще много товарищей, которым не совсем понятны принципы работы этих двух классов. Сегодня я рассмотрю эту концепцию для всех, и автором. способ В J2SE 5.0 появился новый класс символьных операций — StringBuilder. Так в чем же разница между StringBuilder и StringBuffer и классом String, с которым мы впервые познакомились? Какой из них следует использовать в разных ситуациях? Я хотел бы поделиться своими взглядами на эти категории, а также надеюсь, что каждый сможет высказать свое мнение. Каждый совершал ошибки, и их исправление — это хорошая возможность учиться.
Короче говоря, основная разница в производительности между типом String и типом StringBuffer на самом деле заключается в том, что String является неизменяемым объектом (Почему? Спросите разработчиков Java, почему String не является собственным типом?) Поэтому каждый раз, когда тип String изменяется Фактически, это эквивалентно созданию нового объекта String и последующему указанию указателя на новый объект String. Поэтому лучше не использовать String для строк, содержимое которых часто меняет, поскольку каждый раз при создании объекта происходит его изменение. будет влиять на производительность системы, особенно при использовании памяти. Когда объектов, на которые нет ссылок, слишком много, сборщик мусора JVM начнет работать, и скорость определенно будет довольно низкой. Вот пример, который не очень уместен:
Если это так, то после завершения цикла for, если объекты в памяти не были очищены сборщиком мусора, в памяти их будет более 20 000, поразительное число, и если это система, используемая многими человек, то это число не очень велико, поэтому каждый должен быть осторожен при его использовании.
Если вы используете класс StringBuffer, результаты будут разными. Каждый раз результатом будет операция над самим объектом StringBuffer вместо создания нового объекта и последующего изменения ссылки на объект. Поэтому в целом мы рекомендуем использовать StringBuffer, особенно если строковые объекты часто изменяются. В некоторых особых случаях конкатенация строк объектов String фактически интерпретируется JVM как конкатенация объектов StringBuffer, поэтому в этих случаях скорость объектов String не будет медленнее, чем у объектов StringBuffer, и особенно следующие строковые объекты: генерируется. Среди них эффективность String намного быстрее, чем StringBuffer:
Вы будете удивлены, обнаружив, что скорость генерации объектов String S1 просто слишком высока, а на данный момент StringBuffer вообще не имеет преимущества в скорости. На самом деле это уловка JVM. В глазах JVM это так.
Отсюда мы получаем первый вывод: в большинстве случаев StringBuffer > String
И как StringBuilder сравнивается с ними? Позвольте мне сначала кратко представить его. StringBuilder — это новый класс в JDK5.0. Разница между ним и StringBuffer заключается в следующем (источник: JavaWorld):
Java.lang.StringBuffer Потокобезопасная изменяемая последовательность символов. Строковый буфер, аналогичный String, но не подлежащий изменению. Строковые буферы могут безопасно использоваться несколькими потоками. При необходимости эти методы можно синхронизировать, так что все операции над любым конкретным экземпляром выполняются в последовательном порядке, соответствующем порядку вызовов методов, выполняемых каждым задействованным потоком.
Каждый строковый буфер имеет определенную емкость. Пока длина последовательности символов, содержащейся в строковом буфере, не превышает эту емкость, нет необходимости выделять новый внутренний массив буферов. Эта емкость автоматически увеличивается при переполнении внутреннего буфера. Начиная с JDK 5.0, к этому классу был добавлен эквивалентный класс для однопоточного использования — StringBuilder. Класс StringBuilder обычно следует использовать вместо этого класса, поскольку он поддерживает все те же операции, но работает быстрее, поскольку не выполняет синхронизацию.
Но использовать экземпляр StringBuilder с несколькими потоками небезопасно. Если такая синхронизация требуется, рекомендуется использовать StringBuffer.
С учетом вышесказанного, я думаю, каждый может понять разницу между ними, поэтому давайте сделаем общий вывод ниже:
В большинстве случаев StringBuilder > StringBuffer
Следовательно, согласно транзитивной теореме этого неравенства: В большинстве случаев StringBuilder > StringBuffer > String
Теперь, когда у нас есть такие результаты вывода, давайте проведем тест, чтобы проверить:
Тестовый код выглядит следующим образом:
/** Создает новый экземплярtestsb */
Final static int ttime = 10000;//Количество тестовых циклов
публичные тестыb() {
}
публичный недействительный тест (String s) {
длинное начало = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
с += "добавить";
}
долго = System.currentTimeMillis();
System.out.println("Время, используемое операцией типа "+s.getClass().getName()+": " + (over - start) + " миллисекунды" );
}
общественный недействительный тест (StringBuffer s) {
длинное начало = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
s.append("добавить");
}
долго = System.currentTimeMillis();
System.out.println("Время, используемое операцией типа "+s.getClass().getName()+": " + (over - start) + " миллисекунды" );
}
общественный недействительный тест (StringBuilder s) {
длинное начало = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
s.append("добавить");
}
долго = System.currentTimeMillis();
System.out.println("Время, используемое операцией типа "+s.getClass().getName()+": " + (over - start) + " миллисекунды" );
}
// Непосредственно проверяем конкатенацию строк в String
публичный недействительный тест2(){
Строка s2 = «абадф»;
длинное начало = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
Строка s = s2 + s2 + s2;
}
долго = System.currentTimeMillis();
System.out.println("Время, необходимое для работы с типом добавления ссылки на строковый объект: " + (over - start) + " миллисекунды" );
}
публичный недействительный тест3(){
длинное начало = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
String s = «абадф» + «абадф» + «абадф» ;
}
долго = System.currentTimeMillis();
System.out.println("Время добавления строк операции: "+ (over - start) + " миллисекунды" );
}
public static void main(String[] args){
Строка s1="abc";
StringBuffer sb1 = новый StringBuffer("abc");
StringBuilder sb2 = новый StringBuilder("abc");
testsb t = новые тестыsb();
т.тест(с1);
т.тест(sb1);
т.тест(sb2);
т.тест2();
т.тест3();
}
}
Кажется, вы все еще не видите разницы между StringBuffer и StringBuilder. Добавьте ttime в 30000 раз и посмотрите:
Время, необходимое для работы с типом java.lang.String: 53444 миллисекунды. Время, необходимое для работы с типом java.lang.StringBuffer: 15 миллисекунд. Время, необходимое для работы с типом java.lang.StringBuilder: 15 миллисекунд. Время. используется для управления типом добавления ссылки на строковый объект. Затраченное время: 31 миллисекунда. Добавление строк заняло время: 0 миллисекунд.
Разница в производительности между StringBuffer и StringBuilder по-прежнему невелика. Давайте увеличим его до 100000 и посмотрим. Мы не будем сюда добавлять тест для типа String, потому что тестирование такого большого объема данных для типа String будет невозможным. очень медленно...
Время, необходимое для работы с типом java.lang.StringBuffer: 31 миллисекунда. Время, необходимое для работы с типом java.lang.StringBuilder: 16 миллисекунд.
Вы можете увидеть разницу, но многие результаты тестов показывают, что StringBuffer быстрее, чем StringBuilder. Давайте увеличим значение до 1000000 и посмотрим (он не должен давать сбой, верно?):
Время, необходимое для работы с типом java.lang.StringBuffer: 265 миллисекунд. Время, необходимое для работы с типом java.lang.StringBuilder: 219 миллисекунд.
Разниц меньше, а результаты очень стабильны. Давайте посмотрим на это немного крупнее, ttime = 5000000:
・・・・・・ Исключение в потоке "main" java.lang.OutOfMemoryError: пространство кучи Java ・・・・・・
Ха-ха, забудь, я больше не буду это тестировать. По сути, производительность — StringBuilder > StringBuffer > String.