Ist es möglich, eine letzte String-Variable erneut zu referenzieren? Bitte lösche mich, was im gegebenen Programm passiert

8

Ich habe ein und dasselbe Programm auf zwei verschiedene Arten geschrieben und beide geben mir unterschiedliche Ergebnisse. Ich verstehe nicht warum. Bitte korrigieren Sie mich. Im ersten Programm bekomme ich diese Ausgabe

Original: Umesh

Geändert: Xmesh

Und im zweiten Programm bekomme ich diese Ausgabe.

Original: Umesh

Geändert: Umesh

Programm-1

%Vor%

Programm-2

%Vor%     
Umesh 27.08.2015, 17:48
quelle

2 Antworten

5

Ich fange einfach damit an, zu sagen, dass du wirklich, wirklich, nicht mit solchen Saiten herumalbern solltest. : -)

In Ihrem ersten Beispiel "referenzieren" Sie nichts (das heißt, Sie ändern nicht, auf welchen String sich s bezieht), was Sie tun, ist Modifizieren String, auf den es sich bezieht. Obwohl offizielle Strings unveränderlich sind, verwenden Sie Reflection als Hintertür, um die undokumentierten Interna der String -Implementierung in Oracle's JDK zu modifizieren (andere JDKs werden möglicherweise anders implementiert, wodurch dieser Code fehlschlägt). Aber die s -Referenz ist unverändert. Auch bei der Reflektion können Sie den Wert einer lokalen Variablen final nicht ändern. (Sie könnten ein final -Feld durch Reflektion ändern, aber dies würde Sie für die gleichen Inkonsistenzen öffnen, die Sie in diesem Beispiel sehen.)

Was in Ihrem zweiten Beispiel passiert, ist folgendes: Da s eine final Variable ist, geben Sie innerhalb von main einen Literalwert, was den Compiler angeht, ist es eine Kompilierzeitkonstante seit String ist offiziell unveränderlich. Der Compiler ist sich der Strings (sehr) bewusst und macht ein gutes Stück Optimierung um sie herum, indem er "a" + "b" + "c" in einfach "abc" umwandelt. Wenn er später "Original: " + s sieht, kann er einfach "Original: Umesh" dafür ersetzen. Und am Ende, wenn es "Changed: " + s sieht, kann es das mit "Changed: Umesh" ersetzen. Am Ende ist es genau so, als hättest du System.out.println("Original: Umesh"); und System.out.println("Changed: Umesh"); im Quellcode geschrieben.

Der Compiler konnte das im ersten Beispiel nicht tun, weil s ein Argument für die Funktion ist und nicht ein final , das direkt in main deklariert wurde.

Sie können den Unterschied im Bytecode sehen. Kompiliere jeden von ihnen und zerlege sie dann über javac -p SomeClass . Hier ist, was ich bekomme (ich nannte sie Example1 und Example2 ):

%Vor%

und

%Vor%

Beachten Sie, dass wir keine String-Verkettung sehen ( StringBuilder usage). Im zweiten Beispiel hat der Compiler die statischen Strings bei der Kompilierung kombiniert.

    
T.J. Crowder 27.08.2015, 17:56
quelle
0

Im zweiten Fall ist "Changed: " + s eine Konstante Ausdruck , der Wert wird zur Kompilierzeit berechnet. Es muss wie das String-Literal "Changed: Umesh" behandelt werden. (Sie können das durch == testen)

Im ersten Fall sind zwar aggressive Optimierungen auf erlaubt letzte Felder , Sie ändern tatsächlich keine endgültigen Felder. Sie schreiben in ein Array-Element, das nicht endgültig ist. Dieser Schreibvorgang muss für nachfolgende Lesevorgänge im selben Thread sichtbar sein.

    
ZhongYu 27.08.2015 18:32
quelle

Tags und Links