このソース コードは、Java のいくつかの興味深い手法を開きます。一つ一つ調べてみましょう。
まず、コードの流れを理解する必要があります。コードのどの部分が最初に実行されますか?
静的初期化ブロック。なんで?Java 言語仕様 (12.4)を参照してください。
Initialization of a class consists of executing its static initializers and the initializers for static fields (class variables) declared in the class.
そして、それはいつ発生しますか?再びJLS(12.4.1)から:
T is a class and a static method declared by T is invoked.
したがって、 static initiazlier が main メソッドの前に最初に実行されるという結論に達することができます。
現在、これらの 2 つの行はリフレクションを使用しています。
Field value = String.class.getDeclaredField("value");
value.setAccessible(true);
簡単にするために、最初の行を 2 行に分けることができます。
Class<String> c=String.class;
Field value=c.getDeclaredField("value");
1 行目はReflected Class Objectを取得しており、2 行目はクラスのフィールドFieldを表すa を取得しています。valueString
value.setAccessible(true)反映されたクラス オブジェクトが、使用時に Java 言語アクセス チェックを抑制する必要があることを示します (参照)。
問題のNexラインは
value.set("Hello World", value.get("G'Day Mate."));
.set() ドキュメントに飛び込むと、 のset(Object aObject,Object value)バージョンを呼び出していることがわかりますset。は、実際には であるのフィールドの値をvalue.get("G'Day Mate.")返しています。そして、それを呼び出すと、オブジェクトの値フィールドの値がオブジェクトの値フィールドに置き換えられます。"G'Day Mate."valuechar[]set"Hello World""G'Day Mate."
ブロックのstaticコードが説明されています。
主な機能に飛び込みましょう。とてもシンプルです。出力する必要がありますHello, world。しかし、それは出力していG'Day Mateます。なんで?イニシャライザで作成したHello, worldString オブジェクトは、メイン関数で使用しているオブジェクトstaticと同じであるためです。JLSHello, worldに再度相談すると、それが明らかになります
さらに、文字列リテラルは常に String クラスの同じインスタンスを参照します。これは、文字列リテラル (より一般的には、定数式の値である文字列 (§15.28)) が、メソッド String.intern を使用して一意のインスタンスを共有するために「インターン」されているためです。
この答えは、事実をより簡潔に理解するのに役立ちます。
Hello,worldオブジェクトの値を既に に変更しているため、別の値が表示されていますG'Day, Mate。
ただし、メイン関数で使用すると、プールにチェックインするのではなくnew String("Hello world")、の新しいインスタンスを直接作成します。StringしたがってHello world、メイン関数はHello world、値を変更した静的初期化子とは異なります。