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.Stringno sea final, a SafeStringpodría ser igual a a String, y viceversa; porque representarían la misma secuencia de personajes.
¿Qué sucedería si aplicaras interna un SafeString- SafeStringiría al grupo de cadenas de la JVM? El ClassLoadery todos los objetos a los que se hacen SafeStringreferencias 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 SafeStringganaría, tal vez un String, o tal vez un SafeStringcargado 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! = StringEntonces SafeString.intern! = String.intern, Y SafeStringtendrí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.