String
est immuable * mais cela signifie uniquement que vous ne pouvez pas le modifier à l'aide de son API publique.
Ce que vous faites ici, c'est contourner l'API normale, en utilisant la réflexion. De la même manière, vous pouvez modifier les valeurs des énumérations, modifier la table de recherche utilisée dans la zone de saisie automatique entière, etc.
Maintenant, la raison s1
et la s2
valeur de changement, c'est qu'ils se réfèrent tous deux à la même chaîne internée. Le compilateur fait cela (comme mentionné dans d'autres réponses).
La raison s3
n'est pas vraiment un peu surprenante pour moi, car je pensais que cela partagerait le value
tableau ( c'était le cas dans la version précédente de Java , avant Java 7u6). Cependant, en regardant le code source de String
, nous pouvons voir que le value
tableau de caractères pour une sous-chaîne est réellement copié (en utilisant Arrays.copyOfRange(..)
). C'est pourquoi cela reste inchangé.
Vous pouvez installer un SecurityManager
, pour éviter que du code malveillant fasse de telles choses. Mais gardez à l'esprit que certaines bibliothèques dépendent de l'utilisation de ce type d'astuces de réflexion (généralement des outils ORM, des bibliothèques AOP, etc.).
*) J'ai initialement écrit que les String
s ne sont pas vraiment immuables, juste "efficaces immuables". Cela peut être trompeur dans l'implémentation actuelle de String
, où le value
tableau est en effet marqué private final
. Cependant, il convient de noter qu'il n'y a aucun moyen de déclarer un tableau en Java immuable, il faut donc veiller à ne pas l'exposer en dehors de sa classe, même avec les modificateurs d'accès appropriés.
Comme ce sujet semble extrêmement populaire, voici quelques suggestions de lecture supplémentaire: le discours de réflexion sur la folie de Heinz Kabutz de JavaZone 2009, qui couvre beaucoup de questions dans le PO, ainsi que d'autres réflexions ... eh bien ... la folie.
Il explique pourquoi cela est parfois utile. Et pourquoi, la plupart du temps, vous devriez l'éviter. :-)