To fajny artykuł, który przedstawia dwa powody, o których już wspomniano w powyższych odpowiedziach:
- Bezpieczeństwo : system może przekazywać wrażliwe fragmenty informacji tylko do odczytu bez obawy, że zostaną zmienione
- Wydajność : niezmienne dane są bardzo przydatne w zapewnianiu bezpieczeństwa wątków.
I to jest prawdopodobnie najbardziej szczegółowy komentarz w tym artykule. Ma to związek z pulą ciągów w Javie i kwestiami bezpieczeństwa. Chodzi o to, jak zdecydować, co trafia do puli strun. Zakładając, że oba ciągi znaków są równe, jeśli ich sekwencja znaków jest taka sama, wówczas mamy warunek wyścigu określający, kto dotrze tam pierwszy, a wraz z nim kwestie bezpieczeństwa. Jeśli nie, to pula ciągów będzie zawierała zbędne ciągi, co spowoduje utratę korzyści z posiadania jej w pierwszej kolejności. Po prostu przeczytaj to sobie, dobrze?
Rozszerzanie String mogłoby siać spustoszenie wśród równych sobie i stażystów. JavaDoc mówi, że równa się:
Porównuje ten ciąg z określonym obiektem. Wynik jest prawdziwy wtedy i tylko wtedy, gdy argument nie ma wartości null i jest obiektem String, który reprezentuje tę samą sekwencję znaków, co ten obiekt.
Zakładając, że java.lang.String
nie było ostateczne, a SafeString
może równać się a String
i na odwrót; ponieważ reprezentowałyby tę samą sekwencję znaków.
Co by się stało, gdybyś zgłosił się intern
do SafeString
- czy SafeString
trafiłby do puli stringów JVM? ClassLoader
I wszystkich obiektow SafeString
referencje uznane byłyby następnie zablokowane na miejscu przez cały okres JVM. Otrzymasz stan wyścigu o tym, kto może być pierwszym, który internuje sekwencję postaci - może SafeString
wygrałbyś, może String
, a może SafeString
załadowany przez inny program ładujący (a więc inną klasę).
Jeśli wygrałeś wyścig w puli, byłby to prawdziwy singleton, a ludzie mogliby uzyskać dostęp do całego twojego środowiska (piaskownicy) poprzez refleksję i secretKey.intern().getClass().getClassLoader()
.
JVM może też zablokować tę dziurę, upewniając się, że do puli zostały dodane tylko konkretne obiekty typu String (bez podklas).
Jeśli equals zostało zaimplementowane w taki sposób, że SafeString
! = String
Then SafeString.intern
! = String.intern
I SafeString
musiałoby zostać dodane do puli. Pula stałaby się wtedy pulą <Class, String>
zamiast, <String>
a wszystko, czego potrzebujesz, aby wejść do puli, to nowy program ładujący klasy.