String
ist unveränderlich, aber das bedeutet nur, dass Sie es nicht über seine öffentliche API ändern können.
Was Sie hier tun, ist, die normale API zu umgehen, indem Sie Reflexion verwenden. Auf die gleiche Weise können Sie die Werte von Aufzählungstypen ändern, die Suchtabelle, die bei der Integer-Autoboxing verwendet wird, ändern, usw.
Der Grund, warum s1
und s2
ihren Wert ändern, liegt darin, dass sie sich beide auf denselben internierten String beziehen. Der Compiler macht das (wie in anderen Antworten erwähnt).
Der Grund, warum s3
seinen Wert tatsächlich nicht ändert, war für mich etwas überraschend, da ich dachte, dass es das value
-Array teilen würde (das tat es in früheren Versionen von Java, vor Java 7u6). Wenn wir uns jedoch den Quellcode von String
ansehen, können wir sehen, dass das value
-Zeichenarray für einen Teilzeichenfolge tatsächlich kopiert wird (unter Verwendung von Arrays.copyOfRange(..)
). Deshalb bleibt es unverändert.
Sie können einen SecurityManager
installieren, um zu verhindern, dass bösartiger Code solche Dinge tut. Beachten Sie jedoch, dass einige Bibliotheken darauf angewiesen sind, diese Art von Reflexionstricks zu verwenden (typischerweise ORM-Tools, AOP-Bibliotheken, etc).
*) Ich habe ursprünglich geschrieben, dass String
s nicht wirklich unveränderlich sind, sondern nur "effektiv unveränderlich". Dies könnte in der aktuellen Implementierung von String
irreführend sein, da das value
-Array tatsächlich als private final
markiert ist. Es ist jedoch erwähnenswert, dass es in Java keine Möglichkeit gibt, ein Array als unveränderlich zu deklarieren, daher muss darauf geachtet werden, es nicht außerhalb seiner Klasse freizulegen, selbst mit den richtigen Zugriffsmodifikatoren.
Da dieses Thema anscheinend überwältigend beliebt ist, hier einige empfohlene weitere Lektüre: Heinz Kabutz's Reflection Madness Vortrag von der JavaZone 2009, der viele der Probleme im OP behandelt, zusammen mit anderem Reflexions... nun ja... Wahnsinn.
Es wird erklärt, warum dies manchmal nützlich ist. Und warum Sie es die meiste Zeit vermeiden sollten. :-)