String
es inmutable *, pero esto solo significa que no puede cambiarlo utilizando su API pública.
Lo que está haciendo aquí es eludir la API normal, utilizando la reflexión. Del mismo modo, puede cambiar los valores de las enumeraciones, cambiar la tabla de búsqueda utilizada en el autoboxing de enteros, etc.
Ahora, la razón s1
y el s2
valor de cambio, es que ambos se refieren a la misma cadena interna. El compilador hace esto (como se menciona en otras respuestas).
La razón por s3
qué no era en realidad un poco sorprendente para mí, ya que pensé que compartiría el value
array ( lo hizo en la versión anterior de Java , antes 7u6 de Java). Sin embargo, mirando el código fuente de String
, podemos ver que la value
matriz de caracteres para una subcadena se copia (usando Arrays.copyOfRange(..)
). Es por eso que no cambia.
Puede instalar un SecurityManager
, para evitar el código malicioso para hacer tales cosas. Pero tenga en cuenta que algunas bibliotecas dependen del uso de este tipo de trucos de reflexión (generalmente herramientas ORM, bibliotecas AOP, etc.).
*) Inicialmente escribí que los String
s no son realmente inmutables, solo "inmutables efectivos". Esto puede ser engañoso en la implementación actual de String
, donde la value
matriz está realmente marcada private final
. Sin embargo, todavía vale la pena señalar que no hay forma de declarar una matriz en Java como inmutable, por lo que se debe tener cuidado de no exponerla fuera de su clase, incluso con los modificadores de acceso adecuados.
Como este tema parece abrumadoramente popular, aquí hay algunas lecturas adicionales sugeridas: la charla Reflection Madness de Heinz Kabutz de JavaZone 2009, que cubre muchos de los problemas en el OP, junto con otra reflexión ... bueno ... locura.
Cubre por qué esto a veces es útil. Y por qué, la mayoría de las veces, debes evitarlo. :-)