2014-11-02 20 views
14

Kod:Jak działa ten statyczny kod?

public static void main (String[] args){ 
     String a = new String("Hello"); 
     String b = " pardner."; 
     System.out.println(a+b); 
     System.out.println("a.equals(\"Hello\") --> " + (a.equals("Hello"))); 
     System.out.println("a --> " + a); 
} 

static { 
     try { 
      Field value = String.class.getDeclaredField("value"); 
      value.setAccessible(true); 
      value.set("Hello", value.get("Howdy")); 
     } catch (Exception e) { } 
} 

Wynik:

Howdy pardner. 
a.equals("Hello") --> true 
a --> Howdy 

jaki sposób ta zmiana kodu "Hello" na "Cześć" podczas drukowania?

+0

Wykorzystuje odbicie zastąpić każdy łańcuch, który jest „Hello” z „Cześć”. –

+0

To * naprawdę * interesujące! Zauważ, co stanie się, jeśli utworzysz 'String a' * final *. Musi to być jakaś forma optymalizacji kompilatora. –

+2

Powiązane: [1] (http://stackoverflow.com/q/8086065/1391249), [2] (http://stackoverflow.com/q/20036436/1391249) – Tiny

Odpowiedz

6

Spójrz tutaj:

http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Field.html

public void set (Object obj, wartość obiektu)

Ustawia pole reprezentowanego przez ten obiekt polu na określonym obiektu argumentu do określonej nowej wartości. Nowa wartość to automatycznie rozpakowana, jeśli pole bazowe ma typ pierwotny.

get publicznych (Object obj)

Zwraca wartość pola reprezentowanego przez to pole, na określonego obiektu.

Twój blok statyczny zostanie wykonany jako pierwszy.

Wszystkie wystąpienia ciągu znaków zawierające słowo "Hello" zastępowane są przez ciąg "Howdy" przez odbicie przed wykonaniem main().

"Cześć" i "Cześć" odnoszą się do tego samego obiektu. Dlatego s.equals("Hello") wyprowadza true System.out.println(a.equals("Howdy")); również wyprowadziłby true.

Spójrz do procesu realizacji dokładnym: enter image description here

8

Pierwszą rzeczą, która dzieje się swoimi static Wykonuje blok. Przez odbicie zmienia wartość String a na "Howdy" (w rzeczywistości zmienia String"Hello" na "Howdy", ale ma ten sam efekt). Jednakże, można dostać

a.equals("Hello") --> true 

ponieważ kompilator już zastąpił wartość z true. Zrobiłem javap -v i otrzymałem

31: ldc   #75     // String a.equals(\"Hello\") --> true 

Tak właśnie się stało. Jak zauważył w komentarzach, jeśli zmienisz String a do

final String a = "Hello"; 

Ostatnia linia zmienia się

a --> Hello 

z tego samego powodu.

+0

Nie widzę "ostatecznego" zachowanie jak opisałeś to w Javie 7. – Makoto

+0

@Makoto Testowałem z Java 8. Uwaga, musiałem użyć 'końcowego ciągu a =" Hello ";' nie 'końcowego ciągu a = nowego ciągu (" Hello ");' –

+1

Myślę, że literał 'String' będzie wykazywał inne zachowanie niż użycie konstruktora. –

9

Najpierw String literals composed of the same characters resolve to the same instance. Więc w

String one = "hello"; 
String two = "hello"; 

obie zmienne odnoszą się do tego samego obiektu.

Po drugie, static initializer blocks are executed when a class is first loaded (and initialized). Dzieje się to przed wywołaniem jakichkolwiek metod klasowych, tj. przed main.

Third, your Java version's implementation of String, presumably, uses a char\[\] field to store the string of characters. This field is named value.

Jesteś using reflection to retrieve to char[] dla obiektu String odwołuje się String dosłownym "Howdy".

Field value = String.class.getDeclaredField("value"); 
... 
value.get("Howdy") 

i przypisanie go do pola obiektu String odwołuje się String dosłowne "Hello"

value.set("Hello", value.get("Howdy")); 

Teraz, gdy metoda main wykonuje

String a = new String("Hello"); 

String dosłowne "Hello" jest char[] odnosząc się do tego samego obiektu, dla którego yo Ustaw wcześniej pole char[]. Ten char[] zawiera znaki 'H', 'o', 'w', 'd' i 'y' ponieważ została ona podjęta z obiektu String odwołuje dosłownym "Howdy".

Te znaki są kopiowane do nowyString obiektu utworzonego tu

String a = new String("Hello");