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 s1et la s2valeur 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 s3n'est pas vraiment un peu surprenante pour moi, car je pensais que cela partagerait le valuetableau ( 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 valuetableau 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 Strings ne sont pas vraiment immuables, juste "efficaces immuables". Cela peut être trompeur dans l'implémentation actuelle de String, où le valuetableau 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. :-)