Короткий ответ
Строка в 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" — объект не изменён
}
}