私のコードの一部でエラーが見つかったと思いますが、すべての状況で頭が後ろを向いているようには見えません。私よりも賢い人が "はい、これは誤りです"と言うことができますが、私の実装のもう一つの選択肢を提案することは間違いありません。互いに参照する静的フィールドを初期化する際にエラーが発生する
エラーの原因は、2つのクラスの静的フィールドがどのように初期化されるかということです。他方のフィールドを参照して1つ(FooClass
)を初期化し、タイプFoo
のオブジェクトを作成して1つ(MyUtility
)を初期化します。ごめんなさい。説明は私の強みではありませんでした。
私はこの問題を軽減しようと努力していましたが、問題を実証しているようなものがありました。
public class Tester {
static class FooClass {
static final FooClass ITS_FOO = MyUtility.MY_FOO;
}
static class MyUtility {
static final FooClass MY_FOO = new FooClass();
static FooClass create() {
return new FooClass();
}
}
public static void main(String[] args) {
System.out.println("utility's: " + MyUtility.create()); // Line "A"
System.out.println("class's: " + FooClass.ITS_FOO); // Line "B"
}
}
が、私はこのデザインは奇妙に見える実現するが、はるかにそれを正当化しようとしません(実際のコードが構成されている「奇妙」あまりにも、しかしなどさまざまな可視性を持つ別々のクラス内)。私はこれを行うためのより良い方法のための提案には間違いなく感謝します。
問題の要点(少なくともこのプログラムでは)は、FooClass.ITS_FOO
フィールドが行Bが実行されるときにnull
であるということです。私が線Aと線Bの順序を切り替えると、いずれのフィールドもnull
になりません。
私はIn what order do static initializer blocks in Java run?のような質問を見ましたが、それもJava Language Specのどちらも、このような相互参照の初期化がどのように行われるかを記述していません。
残念なことに、このサンプルは実際の実装から削除されていますので、私はたぶん同じソリューションを翻訳するのに同じ時間を費やすことになりますが、それは説明をする価値があります。
残念ながら(あなたの第三型の修正をWRT)、設計の基本的な部分は 'FooClass.ITS_FOO'フィールドは特別な種類のものということです'FooClass'です。私の例を簡略化すると、その事実が取り除かれました:(。しかし、私はまだクラスが初期化される前にコンストラクタを実行できることに驚いています(ただし、この場合は動作させるには魔法のように思えます)。いずれにしても、依存関係の1つを取り除く方法を考えます。これは悪い考え方のように聞こえます... –
@Rob:これは12.4.2節のこのポイントでカバーされています:「CのClassオブジェクトが現在のスレッドによってCの初期化が進行中であることを示している場合、初期化のための再帰的な要求。LCをリリースし、正常に完了してください。 " –
ああ!私は前にその言葉に従っていませんでしたが、今私はこの事件とその "完全に正常な"は誤解を招く... "本当に悪い考え"につながることがわかります。ありがとう! –