Это хорошая статья , в которой изложены две причины, уже упомянутые в ответах выше:
- Безопасность : система может раздавать
чувствительные биты только для чтения
информация, не беспокоясь о том, что
они будут изменены
- Производительность : неизменяемые данные очень
полезен для создания многопоточной среды.
И это, вероятно, самый подробный комментарий в этой статье. Это связано с пулом строк в Java и проблемами безопасности. Это о том, как решить, что входит в пул строк. Предполагая, что обе строки равны, если их последовательность символов одинакова, тогда у нас есть условие расы о том, кто попадет туда первым, и вместе с этим проблемы безопасности. Если нет, то пул строк будет содержать избыточные строки, таким образом, теряя преимущество его наличия в первую очередь. Просто прочитайте это для себя, ладно?
<Ч />
Расширение String может нанести ущерб равным и интерну. JavaDoc говорит, что равно:
Сравнивает эту строку с указанным объектом. Результат имеет значение true тогда и только тогда, когда аргумент не равен NULL и является объектом String, представляющим ту же последовательность символов, что и этот объект.
Предполагая, что java.lang.String
не является окончательным, SafeString
может равняться String
, и наоборот; потому что они будут представлять одну и ту же последовательность символов.
Что бы произошло, если бы вы применили intern
к SafeString
- пойдет ли SafeString
в пул строк JVM? ClassLoader
и все объекты, на которые хранились ссылки SafeString
, будут заблокированы на время жизни JVM. Вы получите условие гонки о том, кто может быть первым, кто интернирует последовательность символов - возможно, ваш SafeString
выиграет, может быть String
, или, возможно, SafeString
, загруженный другим загрузчиком классов (таким образом, другим класс).
Если вы выиграете гонку в пуле, это будет настоящий синглтон, и люди смогут получить доступ ко всей вашей среде (песочнице) с помощью рефлексии и secretKey.intern().getClass().getClassLoader()
.
Или JVM может заблокировать эту дыру, убедившись, что в пул были добавлены только конкретные объекты String (и никаких подклассов).
Если равенство было реализовано так, что SafeString
! = String
, тогда SafeString.intern
! = String.intern
и SafeString
должны были бы быть добавлены в пул. Тогда пул станет пулом <Class, String>
вместо <String>
, и все, что вам потребуется для входа в пул, - это новый загрузчик классов.