String
è immutabile * ma ciò significa solo che non è possibile modificarlo utilizzando la sua API pubblica.
Quello che stai facendo qui è aggirare l'API normale, usando la riflessione. Allo stesso modo, è possibile modificare i valori degli enum, modificare la tabella di ricerca utilizzata nell'autoboxing intero, ecc.
Ora, la ragione s1
e il s2
valore di modifica, è che entrambi si riferiscono alla stessa stringa internata. Il compilatore fa questo (come indicato da altre risposte).
Il motivo s3
non è stato in realtà un po 'sorprendente per me, poiché pensavo che avrebbe condiviso l' value
array ( lo faceva nella versione precedente di Java , prima di Java 7u6). Tuttavia, osservando il codice sorgente di String
, possiamo vedere che l' value
array di caratteri per una sottostringa viene effettivamente copiato (usando Arrays.copyOfRange(..)
). Questo è il motivo per cui rimane invariato.
È possibile installare un SecurityManager
, per evitare che codice dannoso esegua tali operazioni. Ma tieni presente che alcune librerie dipendono dall'uso di questo tipo di trucchi di riflessione (in genere strumenti ORM, librerie AOP ecc.).
*) Inizialmente ho scritto che String
non sono veramente immutabili, solo "efficaci immutabili". Ciò potrebbe essere fuorviante nell'attuale implementazione di String
, dove l' value
array è effettivamente contrassegnato private final
. Vale comunque la pena notare che non c'è modo di dichiarare immutabile un array in Java, quindi bisogna fare attenzione a non esporlo al di fuori della sua classe, anche con i modificatori di accesso appropriati.
Dato che questo argomento sembra estremamente popolare, ecco alcuni suggerimenti suggeriti da leggere ulteriormente: il discorso Reflection Madness di Heinz Kabutz da JavaZone 2009, che copre molti problemi dell'OP, insieme ad altre riflessioni ... beh ... follia.
Copre il motivo per cui a volte questo è utile. E perché, il più delle volte, dovresti evitarlo. :-)