Короткий ответ
Строка в Java неизменяема, потому что после создания объекта String его содержимое изменить нельзя: методы, которые выглядят как изменение (concat, replace, substring, toUpperCase), возвращают новый объект, а исходный остаётся нетронутым. Технически это обеспечивают final-массив символов с инкапсуляцией и final-класс, запрещающий наследование.
Как это работает подробнее
Неизменяемость — продуманное решение разработчиков языка: она делает строки безопасными для кэширования, разделения между потоками и хранения чувствительных данных. Хэш-код вычисляется один раз и сохраняется, строки надёжно интернируются и переиспользуются в пуле, а ключ коллекции не меняется после вставки.
- Кэширование hashCode — значение вычисляется один раз и сохраняется в поле, вызовы при работе с HashMap и HashSet не пересчитывают его.
- Пул строк и интернирование — неизменяемые литералы безопасно переиспользовать: одна «испорченная» строка не повлияет на все места использования.
- Стабильные ключи — ключ не меняется после вставки, иначе изменился бы хэш и запись в HashMap «потерялась».
- Потокобезопасность — неизменяемый объект можно разделять между потоками без синхронизации, гонок данных нет.
- Надёжность и безопасность — пароли, URL, имена классов и файлов можно передавать по ссылкам, не опасаясь изменения «за спиной».
Пример кода
StringDemo.java
public class StringDemo {
public static void main(String[] args) {
String s = "Hello";
s.concat(" World"); // создаёт новую строку "Hello World"
System.out.println(s); // а s останется "Hello" — объект не изменён
}
}Что использовать на практике
- Используй String, когда строка не меняется: это безопасно и эффективно.
- При частых модификациях бери StringBuilder, а StringBuffer — только при реальном доступе из нескольких потоков.
- Строки можно смело использовать как ключи коллекций и передавать между потоками.
Подводные камни
- Каждая операция «изменения» создаёт новый объект: конкатенация через + в цикле плодит множество временных строк.
- Компилятор собирает простую конкатенацию в StringBuilder, но в цикле это не спасает от создания объектов.
- Неизменяем объект, а не переменная: ссылку на String можно свободно переназначать на другую строку.
Как отвечать на собеседовании
- Дай определение: содержимое нельзя изменить после создания → назови технические причины (final-массив, инкапсуляция, final-класс) → перечисли выгоды: кэш hashCode, пул строк, стабильные ключи, потоки, пароли и URL → укажи плату (новые объекты) → подведи к StringBuilder и StringBuffer.