Відповіді:
Різниця змінності:
Stringє незмінним , якщо ви намагаєтесь змінити їх значення, створюється інший об'єкт, тоді як StringBufferі StringBuilderє змінним , так що вони можуть змінити їх значення.
Різниця безпеки -
Різниця між StringBufferі StringBuilderполягає в тому, що StringBufferбезпечно для потоків. Тож коли додаток потрібно запускати лише в один потік, тоді краще використовувати StringBuilder. StringBuilderє більш ефективним, ніж StringBuffer.
Ситуації:
Stringоб'єкт є незмінним.StringBuilder, досить добре.StringBufferоскільки StringBufferце синхронізовано, щоб у вас була безпека потоку.Stringsколи ми змінюємо значення, створюється інший об’єкт. Чи дана посилання на старий об'єкт є недійсною, щоб воно могло бути зібране сміттям GCабо навіть зібране сміття?
Stringз StringBuilder?
Stringколи незмінна структура доречна; отримання нової послідовності символів від aString може спричинити неприйнятне покарання за продуктивність, як у процесі процесора, так і в пам’яті (отримання підрядків є ефективним процесором, тому що дані не копіюються, але це означає, що може залишатися виділений значно більший обсяг даних).StringBuilderколи вам потрібно створити змінну послідовність символів, як правило, щоб об'єднати кілька послідовностей символів разом.StringBufferв тих самих обставинах, що і ви StringBuilder, але коли зміни в нижній строці повинні бути синхронізовані (оскільки декілька потоків читають / змінюютьбуфер буфера).Дивіться приклад тут .
Основи:
Stringце незмінний клас, його неможливо змінити.
StringBuilder- це клас, що змінюється, до якого можна додати, символи замінено або видалити і в кінцевому підсумку перетворити на а String
StringBuffer- це оригінальна синхронізована версіяStringBuilder
Вам слід віддати перевагу StringBuilderв усіх випадках, коли у вас є лише одна нитка, що отримує доступ до вашого об'єкта.
Деталі:
Також зауважте, що StringBuilder/Buffers це не магія, вони просто використовують масив як резервний об'єкт, і що масив повинен бути перерозподілений, коли він заповниться. Будьте впевнені та створюйте свої StringBuilder/Bufferоб'єкти достатньо великими спочатку там, де їх не потрібно постійно змінювати за розміром кожного разу, коли вас .append()викликають.
Повторне розмір може стати дуже виродженим. В основному він переозброює резервний масив у 2 рази більше його поточного розміру кожного разу, коли його потрібно розширювати. Це може призвести до того, що велика кількість оперативної пам’яті буде виділено і не використовується, колиStringBuilder/Buffer заняття починають зростати.
У Java String x = "A" + "B";використовується StringBuilderкулуар. Так що для простих випадків немає користі заявляти про своє. Але якщо ви будуєте Stringоб'єкти з великими розмірами, скажімо, меншими за 4 кк, то декларування StringBuilder sb = StringBuilder(4096);набагато ефективніше, ніж конкатенація або використання конструктора за замовчуванням, який становить лише 16 символів. Якщо у вас Stringбуде менше 10 к, тоді ініціалізуйте його з конструктором до 10 к, щоб бути безпечним. Але якщо це ініціалізація до 10k, то ви пишете на 1 символ більше 10k, він буде перерозподілений та скопійований у масив 20k. Тож ініціалізація високого краще, ніж низького.
У випадку автоматичного зміни розміру на 17-му символі резервний масив перерозподіляється та копіюється на 32 символи, у 33-го символу це повторюється, і ви отримуєте можливість перерозподілити та скопіювати масив на 64 символи. Ви можете бачити, як це вироджується до безлічі перерозподілів та копій, що ви справді намагаєтесь уникати використання StringBuilder/Bufferв першу чергу.
Це з вихідного коду JDK 6 для AbstractStringBuilder
void expandCapacity(int minimumCapacity) {
int newCapacity = (value.length + 1) * 2;
if (newCapacity < 0) {
newCapacity = Integer.MAX_VALUE;
} else if (minimumCapacity > newCapacity) {
newCapacity = minimumCapacity;
}
value = Arrays.copyOf(value, newCapacity);
}
Найкраща практика - ініціалізувати StringBuilder/Bufferтрохи більший розмір, ніж ти думаєш, що тобі знадобиться, якщо ти не знаєш прямо, наскільки великою Stringбуде воля, але ти можеш здогадатися. Один розподіл трохи більше пам’яті, ніж потрібно, буде кращим, ніж безліч перерозподілів та копій.
Також остерігайтеся ініціалізації символу a StringBuilder/Bufferз String, який буде виділяти лише розмір String + 16 символів, що в більшості випадків просто запустить вироджений цикл перерозподілу та копіювання, яких ви намагаєтеся уникнути. Далі йде прямо з вихідного коду Java 6.
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
Якщо ви випадково опинитесь на екземплярі, StringBuilder/Bufferякий ви не створили і не можете керувати конструктором, який викликається, є спосіб уникнути виродженої поведінки перерозподілу та копіювання. Зателефонуйте .ensureCapacity()в той розмір, який ви хочете, щоб переконатися, що ваш результат Stringпідходить.
Альтернативи:
Як зауваження, якщо ви робите по-справжньому важкі String будівництво та маніпуляції, існує набагато більш орієнтована на ефективність альтернатива під назвою Мотузки .
Інша альтернатива - створити StringListімплементацію шляхом підкласифікації ArrayList<String>та додавання лічильників для відстеження кількості символів у всіх .append()та інших операціях з мутації списку, а потім замінити .toString()для створення StringBuilderпотрібного вам потрібного розміру та прокрутити список та скласти Вихід, ви навіть можете зробити цю StringBuilderзмінну екземпляра і "кешувати" результати, .toString()і лише повторно генерувати їх, коли щось зміниться.
Також не забувайте про String.format()створення фіксованого форматованого виводу, який може бути оптимізований компілятором, оскільки вони покращують його.
String x = "A" + "B";справді компілюється як StringBuilder? Чому б його не просто компілювати String x = "AB";, він повинен використовувати StringBuilder, лише якщо компоненти не відомі під час компіляції.
Ви маєте на увазі конкатенацію?
Приклад із реального світу: Ви хочете створити нову рядок із багатьох інших .
Наприклад, щоб надіслати повідомлення:
Рядок
String s = "Dear " + user.name + "<br>" +
" I saw your profile and got interested in you.<br>" +
" I'm " + user.age + "yrs. old too"
StringBuilder
String s = new StringBuilder().append.("Dear ").append( user.name ).append( "<br>" )
.append(" I saw your profile and got interested in you.<br>")
.append(" I'm " ).append( user.age ).append( "yrs. old too")
.toString()
Або
String s = new StringBuilder(100).appe..... etc. ...
// The difference is a size of 100 will be allocated upfront as fuzzy lollipop points out.
StringBuffer (синтаксис точно такий, як у StringBuilder, ефекти відрізняються)
Про
StringBuffer vs. StringBuilder
Перший синхронізований, а пізніше - ні.
Отже, якщо ви будете викликати його кілька разів в одному потоці (що становить 90% випадків), StringBuilderвін запуститься набагато швидше, оскільки він не зупиниться, щоб побачити, чи є у нього блокування потоку.
Отже, його рекомендується використовувати StringBuilder(якщо, звичайно, у вас є одночасно більше ніж один потік), що рідко)
Stringконкатенація ( за допомогою оператора + ) може бути оптимізована компілятором для використання StringBuilderвнизу, тож, це вже не про що турбуватися, в старіші дні Java це було те, про що всі кажуть, що слід уникати будь-якої ціни, тому що кожного конкатенації створили новий об'єкт String. Сучасні компілятори більше не роблять цього, але все-таки є хорошою практикою використовувати StringBuilderнатомість на випадок, якщо ви використовуєте "старий" компілятор.
редагувати
Тільки для тих, хто цікавий, ось що робить компілятор для цього класу:
class StringConcatenation {
int x;
String literal = "Value is" + x;
String builder = new StringBuilder().append("Value is").append(x).toString();
}
javap -c StringConcatenation
Compiled from "StringConcatenation.java"
class StringConcatenation extends java.lang.Object{
int x;
java.lang.String literal;
java.lang.String builder;
StringConcatenation();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: new #2; //class java/lang/StringBuilder
8: dup
9: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
12: ldc #4; //String Value is
14: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_0
18: getfield #6; //Field x:I
21: invokevirtual #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
24: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: putfield #9; //Field literal:Ljava/lang/String;
30: aload_0
31: new #2; //class java/lang/StringBuilder
34: dup
35: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
38: ldc #4; //String Value is
40: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
43: aload_0
44: getfield #6; //Field x:I
47: invokevirtual #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
50: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
53: putfield #10; //Field builder:Ljava/lang/String;
56: return
}
Рядки з цифрами 5 - 27 призначені для рядка під назвою "буквальний"
Рядки з номером 31-53 призначені для рядка під назвою "builder"
Ther не має різниці, точно однаковий код виконується для обох рядків.
StringBuilderоб'єднання рядків String в правій частині завдання. Будь-яка хороша реалізація використовуватиме StringBuilder за кадром, як ви кажете. Крім того, ваш приклад "a" + "b"буде складений в один буквальний, "ab"але якщо ви використовуєте, StringBuilderце призведе до двох зайвих дзвінків на append().
"a"+"b"але щоб сказати, що було об'єднанням String, я змінив це на явне. Чого ти не кажеш, чому це не є хорошою практикою цього робити. Саме так робить (сучасний) компілятор. @fuzzy, погоджуюся, спеціально, коли ви знаєте, який би розмір остаточного рядка (aprox).
-------------------------------------------------- --------------------------------
String StringBuffer StringBuilder
-------------------------------------------------- --------------------------------
Зберігання | Постійний струнний басейн Heap Heap
Модифікується | Ні (незмінний) Так (змінний) Так (змінний)
Нитка безпечна | Так Так Ні
Продуктивність | Швидкий Дуже повільний Швидкий
-------------------------------------------------- --------------------------------
synchronisedі ось чому .
Рядок
String classЯвляє собою рядок символів. Всі рядкові літерали в програмі Java, такі як "abc"реалізовані як екземпляри цього класу.
Об'єкти струни незмінні після їх створення ми не можемо змінити. ( Струни - константи )
Якщо рядок створюється з допомогою конструктора або методу , то ці рядки будуть зберігатися в динамічної пам'яті , а також SringConstantPool. Але перед збереженням у пулі він запускає intern()метод перевірити наявність об'єкта з однаковим вмістом у пулі, використовуючи метод рівняння. Якщо String-copy доступний у пулі, то повертає посилання. В іншому випадку об'єкт String додається до пулу і повертає посилання.
+) та перетворення інших об'єктів у рядки. Зв'язування рядків реалізується через клас StringBuilder (або StringBuffer) та його метод додавання.String heapSCP = new String("Yash");
heapSCP.concat(".");
heapSCP = heapSCP + "M";
heapSCP = heapSCP + 777;
// For Example: String Source Code
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
Літеральні рядки зберігаються в StringConstantPool.
String onlyPool = "Yash";
StringBuilder і StringBuffer - це змінна послідовність символів. Це означає, що можна змінити значення цих об'єктів. StringBuffer має ті самі методи, що і StringBuilder, але кожен метод у StringBuffer синхронізований, таким чином, він є безпечним для потоків.
Дані StringBuffer і StringBuilder можна створити лише за допомогою нового оператора. Отже, вони зберігаються в пам'яті Heap.
Примірники StringBuilder не безпечні для використання кількома потоками. Якщо потрібна така синхронізація, рекомендується використовувати StringBuffer.
StringBuffer threadSafe = new StringBuffer("Yash");
threadSafe.append(".M");
threadSafe.toString();
StringBuilder nonSync = new StringBuilder("Yash");
nonSync.append(".M");
nonSync.toString();
StringBuffer і StringBuilder надають спеціальні методи , такі як.,
replace(int start, int end, String str)І reverse().
ПРИМІТКА : StringBuffer і SringBuilder є зміненими, оскільки вони забезпечують реалізацію
Appendable Interface.
Коли використовувати який.
Якщо ви не збираєтесь змінювати значення кожен раз, тоді його краще використовувати String Class. Як частина Generics, якщо ви хочете сортувати Comparable<T>або порівнювати значення, тоді переходьте String Class.
//ClassCastException: java.lang.StringBuffer cannot be cast to java.lang.Comparable
Set<StringBuffer> set = new TreeSet<StringBuffer>();
set.add( threadSafe );
System.out.println("Set : "+ set);
Якщо ви збираєтесь змінювати значення кожного разу, перейдіть на StringBuilder, який швидше, ніж StringBuffer. Якщо кілька потоків змінюють значення, перейдіть для StringBuffer.
Крім того, StringBufferє безпечним для ниток, чого StringBuilderнемає.
Тож у ситуації в реальному часі, коли до нього звертаються різні потоки, це StringBuilderможе мати неефективні результати.
Зауважте, що якщо ви використовуєте Java 5 або новішу версію, слід використовувати її StringBuilderзамість StringBuffer. З документації API:
Починаючи з версії JDK 5, цей клас був доповнений еквівалентним класом , призначеного для використання в одному потоці,
StringBuilder.StringBuilderКлас , як правило , повинні бути використані в перевазі до цього, так як вона підтримує все ті ж операції , але це швидше, так як він не виконує синхронізацію.
На практиці ви майже ніколи не будете використовувати це з декількох потоків одночасно, тому синхронізація, яка StringBufferце робиться, майже завжди зайва накладні витрати.
Особисто я не думаю, що для цього немає жодного реального використання StringBuffer. Коли мені хотілося б спілкуватися між декількома потоками, маніпулюючи послідовністю символів? Це зовсім не здається корисним, але, можливо, мені ще належить побачити світло :)
Різниця між String та іншими двома класами полягає в тому, що String є незмінним, а інші два - класами, що змінюються.
Але чому ми маємо два класи з однаковою метою?
Причина в тому, що StringBufferнитка безпечна і StringBuilderні.
StringBuilderце новий клас, StringBuffer Apiі він був введений в JDK5і завжди рекомендується, якщо ви працюєте в єдиному потоковому середовищі, оскільки це багатоFaster
Для отримання повної інформації ви можете прочитати http://www.codingeek.com/java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-java/
У java String незмінна. Будучи непорушним, ми маємо на увазі, що після створення String ми не можемо змінити її значення. StringBuffer можна змінювати. Після створення об’єкта StringBuffer ми просто додаємо вміст до значення об'єкта замість створення нового об'єкта. StringBuilder схожий на StringBuffer, але він не є безпечним для потоків. Методи StingBuilder не синхронізовані, але порівняно з іншими струнами Stringbuilder працює найшвидше. Ви можете дізнатися різницю між String, StringBuilder і StringBuffer , реалізуючи їх.