← Назад к вопросам
Что будет если выполнить команду a += d, где a и d - строки?
1.0 Junior🔥 181 комментариев
#ORM и Hibernate#Spring Boot и Spring Data#Базы данных и SQL
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Операция += со строками в Java
Это классический вопрос на собеседованиях, который проверяет понимание работы строк в Java и того, как компилятор оптимизирует операции конкатенации.
Простой ответ
String a = "Hello";
String d = " World";
a += d;
System.out.println(a); // Hello World
Результат: переменная a содержит новую строку "Hello World".
Но что происходит на самом деле?
Это не просто конкатенация на месте — это создание новой строки с присваиванием.
String a = "Hello";
String d = " World";
// a += d эквивалентно:
// a = a + d
// Что происходит step by step:
// 1. Создается новая строка: a.concat(d)
// 2. Результат присваивается переменной a
a = a + d;
System.out.println(a); // "Hello World"
Как это работает: StringBuilder за кулисами
Java компилятор оптимизирует строковую конкатенацию:
// Исходный код
String a = "Hello";
String d = " World";
a += d;
// Что компилятор компилирует (bytecode):
String a = "Hello";
String d = " World";
a = new StringBuilder()
.append(a) // Append исходной строки
.append(d) // Append добавляемой строки
.toString(); // Преобразование в String
Если бы это было в цикле:
// ❌ ПЛОХО - неэффективно
String result = "";
for (int i = 0; i < 1000; i++) {
result += "x"; // Создает 1000 новых StringBuilder объектов!
}
// Компилятор переводит в:
String result = "";
for (int i = 0; i < 1000; i++) {
result = new StringBuilder()
.append(result)
.append("x")
.toString(); // новый объект каждый раз
}
// Это O(n²) операция!
// ✅ ХОРОШО - эффективно
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 1000; i++) {
builder.append("x");
}
String result = builder.toString();
// O(n) операция
Важные детали
1. String immutable (неизменяемая)
String a = "Hello";
String d = " World";
String original = a; // Сохраняем ссылку на исходную строку
a += d; // Создает новую строку
System.out.println(original); // "Hello" - не изменилась!
System.out.println(a); // "Hello World"
// original и a указывают на разные объекты
System.out.println(original == a); // false
System.out.println(original.equals(a)); // false
2. Почему String immutable?
public class StringImmutabilityBenefits {
/**
* Преимущества immutable строк:
*
* 1. Thread safety - не нужно синхронизация
* String можно безопасно передавать между потоками
*
* 2. String pooling - Java может reuse строки
* String s1 = "Hello";
* String s2 = "Hello"; // Может быть тот же объект
*
* 3. Security - HashMap keys, passwords, credentials
* Нельзя случайно изменить критические данные
*
* 4. Performance - hashCode может кэшироваться
* Для HashMap/HashSet это важно
*/
}
// Пример pooling
String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");
System.out.println(s1 == s2); // true - из pool
System.out.println(s1 == s3); // false - new объект
System.out.println(s1.equals(s3)); // true - содержимое одинаково
3. Производительность в разных ситуациях
public class StringConcatenationPerformance {
// Сценарий 1: Одна операция += (хорошо)
public String scenario1() {
String a = "Hello";
String d = " World";
a += d; // Оптимизировано в StringBuilder
return a; // "Hello World"
}
// Сценарий 2: Несколько += (хорошо - компилятор объединит)
public String scenario2() {
String result = "Hello";
result += " ";
result += "World";
result += "!";
return result;
// Компилятор создаст один StringBuilder для всех
}
// Сценарий 3: Цикл с += (плохо - создает объект на каждой итерации)
public String scenario3() {
String result = "";
for (int i = 0; i < 1000; i++) {
result += i; // ПЛОХО!
}
return result;
}
// Сценарий 4: Цикл со StringBuilder (хорошо)
public String scenario4() {
StringBuilder result = new StringBuilder();
for (int i = 0; i < 1000; i++) {
result.append(i); // ХОРОШО
}
return result.toString();
}
}
Null и пустые строки
// Случай 1: null значение
String a = null;
String d = " World";
a += d; // Что будет?
// Java конвертирует:
// a = a + d;
// a = null + " World";
// a = "null World"; // null конвертируется в строку "null"
System.out.println(a); // "null World"
// Случай 2: пустая строка
String a = "";
String d = "Hello";
a += d;
System.out.println(a); // "Hello" - просто добавилась строка
// Случай 3: обе пустые
String a = "";
String d = "";
a += d;
System.out.println(a); // "" - остается пустой
System.out.println(a == ""); // true - может быть из pool
Сравнение с другими типами
public class PlusOperatorComparison {
// Со строками - создает новую строку
public void stringConcatenation() {
String a = "Hello";
String d = " World";
a += d; // Новая строка
}
// С числами - выполняет арифметическую операцию
public void numberAddition() {
int a = 5;
int d = 3;
a += d; // a = 8, та же переменная (примитив, не объект)
}
// Со StringBuilder - модификация на месте
public void stringBuilder() {
StringBuilder a = new StringBuilder("Hello");
String d = " World";
a.append(d); // Модифицируется существующий объект!
// a указывает на тот же объект StringBuilder
}
}
Bytecode уровень
// Как это выглядит в bytecode
public class StringConcatBytecode {
public static void main(String[] args) {
String a = "Hello";
String d = " World";
a += d;
}
}
// Эквивалентный bytecode (упрощенно):
// 1. Создать StringBuilder
// 2. Append a
// 3. Append d
// 4. toString()
// 5. Присвоить результат переменной a
Оптимизация в Java 9+
Java 9 добавила invokedynamic для более эффективной конкатенации:
// В Java 8 и раньше - явное использование StringBuilder
// В Java 9+ - компилятор использует более оптимальные методы
// через MethodHandle и ByteCodeGenerator
// Результат - эффективнее памяти и быстрее работает
String a = "Hello";
String d = " World";
a += d; // Работает еще быстрее в Java 21!
Практические рекомендации
public class StringConcatBestPractices {
// ❌ ПЛОХО - в цикле
public String badWay(List<String> items) {
String result = "";
for (String item : items) {
result += item + ",";
}
return result;
}
// ✅ ХОРОШО - используй StringBuilder
public String goodWay(List<String> items) {
StringBuilder sb = new StringBuilder();
for (String item : items) {
sb.append(item).append(",");
}
return sb.toString();
}
// ✅ ХОРОШО - использую String.join()
public String betterWay(List<String> items) {
return String.join(",", items);
}
// ✅ ХОРОШО - используй String format
public String anotherGood(String name, int age) {
return String.format("Name: %s, Age: %d", name, age);
}
// ✅ ХОРОШО - Java 15+ text block (multiline)
public String textBlock() {
String html = """
<div>
<h1>Hello</h1>
<p>World</p>
</div>
""";
return html;
}
}
Заключение
Когда вы выполняете a += d со строками:
- Java создает новую строку, не изменяет старую (immutable)
- Компилятор оптимизирует это в StringBuilder
- На памяти создается новый объект String
- Старая ссылка перенаправляется на новый объект
- В циклах это может быть неэффективно - используйте StringBuilder
- На современном Java эта оптимизация очень быстрая
Ключевое правило: помните про immutability строк и используйте StringBuilder когда нужна конкатенация в цикле.