Это хорошая статья, в которой изложены две причины, уже упомянутые в ответах выше:
- Безопасность : система может передавать конфиденциальные биты информации только для чтения, не беспокоясь о том, что они будут изменены.
- Производительность : неизменяемые данные очень полезны для обеспечения потоковой безопасности.
И это, наверное, самый подробный комментарий в той статье. Это связано с пулом строк в Java и проблемами безопасности. Речь идет о том, как решить, что входит в пул строк. Предполагая, что обе строки равны, если их последовательность символов одинакова, тогда у нас есть условие гонки на то, кто попадет первым, а также проблемы безопасности. Если нет, то пул строк будет содержать избыточные строки, что приведет к потере преимущества его наличия. Просто прочти это для себя, а?
Расширение String нанесло бы ущерб равным и стажерам. JavaDoc говорит, что равно:
Сравнивает эту строку с указанным объектом. Результат истинен тогда и только тогда, когда аргумент не равен нулю и является объектом String, который представляет ту же последовательность символов, что и этот объект.
Предполагая, что java.lang.String
не является окончательным, a SafeString
может быть равно a 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>
и все, что вам нужно, чтобы войти в пул, - это новый загрузчик классов.