Este es un buen artículo que describe dos razones ya mencionadas en las respuestas anteriores:
- Seguridad : el sistema puede entregar fragmentos sensibles de información de solo lectura sin preocuparse de que se modifiquen
- Rendimiento : los datos inmutables son muy útiles para hacer que las cosas sean seguras para subprocesos.
Y este es probablemente el comentario más detallado en ese artículo. Tiene que ver con el conjunto de cadenas en Java y los problemas de seguridad. Se trata de cómo decidir qué entra en el conjunto de cadenas. Suponiendo que ambas cadenas son iguales si su secuencia de caracteres es la misma, entonces tenemos una condición de carrera sobre quién llega primero y junto con los problemas de seguridad. De lo contrario, el conjunto de cadenas contendrá cadenas redundantes, perdiendo así la ventaja de tenerlo en primer lugar. Solo léelo por ti mismo, ¿quieres?
La extensión de String causaría estragos en iguales e internos. JavaDoc dice igual a:
Compara esta cadena con el objeto especificado. El resultado es verdadero si y solo si el argumento no es nulo y es un objeto String que representa la misma secuencia de caracteres que este objeto.
Suponiendo que java.lang.String
no sea final, a SafeString
podría ser igual a a String
, y viceversa; porque representarían la misma secuencia de personajes.
¿Qué sucedería si aplicaras intern
a un SafeString
- SafeString
iría al grupo de cadenas de la JVM? El ClassLoader
y todos los objetos a los que se hacen SafeString
referencias se bloquearían en su lugar durante la vida útil de la JVM. Tendría una condición de carrera sobre quién podría ser el primero en internar en una secuencia de personajes: tal vez SafeString
ganaría, tal vez un String
, o tal vez un SafeString
cargado por un cargador de clases diferente (por lo tanto, una clase diferente).
Si ganaras la carrera en el grupo, este sería un verdadero singleton y las personas podrían acceder a todo tu entorno (caja de arena) a través de la reflexión y secretKey.intern().getClass().getClassLoader()
.
O la JVM podría bloquear este agujero asegurándose de que solo se agregaron objetos de String concretos (y no subclases) al grupo.
Si equals se implementó de manera que SafeString
! = String
Entonces SafeString.intern
! = String.intern
, Y SafeString
tendría que agregarse al grupo. El grupo se convertiría en un grupo de en <Class, String>
lugar de <String>
y todo lo que necesitaría para ingresar al grupo sería un nuevo cargador de clases.