Відповіді:
Різниця змінності:
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 , реалізуючи їх.