Почему строки в Java сделаны immutable
Что проверяют
Знаете ли вы конкретные механизмы, которые держатся на неизменяемости, а не общие слова про безопасность. Следом спрашивают про пул строк и почему пароль хранят в char[], а не в String.
Как отвечать
Начните с того, чем неизменяемость обеспечена: класс String объявлен final, поле с содержимым тоже final и наружу не отдаётся, конструкторы копируют переданный массив. С Java 9 внутри лежит byte[] плюс признак кодировки (Compact Strings), латиница занимает байт на символ.
Дальше причины:
- пул строк: одинаковые литералы это один объект в куче. Разделять его можно только потому, что изменить нельзя, иначе правка в одном месте поменяла бы значение везде;
- кэш
hashCode: хеш считается один раз и хранится в поле, поэтомуStringдёшев как ключHashMap. У изменяемого ключа хеш уехал бы, и запись стала бы недостижимой; - потокобезопасность даром: неизменяемый объект читается из любого числа потоков без синхронизации и гонок при публикации;
- безопасность: имена классов при загрузке, пути к файлам, строки подключения. Будь строка изменяемой, значение подменили бы между проверкой и использованием;
- предсказуемость API: строку можно принять и отдать наружу без защитного копирования.
Плата очевидна: любое «изменение» создаёт новый объект, поэтому конкатенация в цикле порождает мусор и там нужен StringBuilder. А выражение a + b + c с Java 9 компилируется в invokedynamic через StringConcatFactory и собирается за один проход, переписывать его руками смысла нет.
Хорошее завершение про пароли: строку нельзя затереть, она живёт до сборки мусора и может оказаться в пуле, поэтому пароль читают в char[] и обнуляют после проверки.
Где спотыкаются
Путают final и неизменяемость. final String s запрещает переприсвоить ссылку, а неизменяемость даёт устройство класса, а не модификатор переменной.
Утверждают, что пул строк лежит в PermGen. Он переехал в обычную кучу ещё в Java 7, а PermGen убрали в Java 8.
Сводят всё к производительности. Выигрышей два: безопасное разделение объекта (пул, потоки) и кэш хеша. И забывают обратную сторону, где неизменяемость дороже, например конкатенацию в цикле.