互いに参照する 2 つの列挙型を持つことによって引き起こされるクラスの読み込みの問題を回避する方法はありますか?
次のように定義された Foo と Bar の 2 つの列挙セットがあります。
public class EnumTest {
public enum Foo {
A(Bar.Alpha),
B(Bar.Delta),
C(Bar.Alpha);
private Foo(Bar b) {
this.b = b;
}
public final Bar b;
}
public enum Bar {
Alpha(Foo.A),
Beta(Foo.C),
Delta(Foo.C);
private Bar(Foo f) {
this.f = f;
}
public final Foo f;
}
public static void main (String[] args) {
for (Foo f: Foo.values()) {
System.out.println(f + " bar " + f.b);
}
for (Bar b: Bar.values()) {
System.out.println(b + " foo " + b.f);
}
}
}
上記のコードは、次の出力を生成します。
A bar Alpha
B bar Delta
C bar Alpha
Alpha foo null
Beta foo null
Delta foo null
なぜそれが起こるのか理解しています - JVM は Foo のクラスローディングを開始します。Foo.A のコンストラクターで Bar.Alpha を認識し、Bar のクラスローディングを開始します。Bar.Alpha のコンストラクターへの呼び出しで Foo.A 参照が確認されますが、(まだ Foo.A のコンストラクターにいるため) Foo.A はこの時点で null であるため、Bar.Alpha のコンストラクターには null が渡されます。2 つの for ループを逆にすると (または、Foo の前に Bar を参照すると)、Bar の値はすべて正しくなるように出力が変更されますが、Foo の値は正しくありません。
これを回避する方法はありますか?静的マップと 3 番目のクラスで静的マップを作成できることはわかっていますが、それはかなりハックな気がします。外部マップを参照する Foo.getBar() および Bar.getFoo() メソッドを作成することもできるので、インターフェイス (パブリック フィールドの代わりにインスペクターを使用している実際のクラス) も変更されませんが、それでも感じられます。私にはちょっと不潔です。
(実際のシステムでこれを行っている理由: Foo と Bar は、2 つのアプリが相互に送信するメッセージのタイプを表します。Foo.b フィールドと Bar.f フィールドは、特定のメッセージに対して予想される応答タイプを表します。サンプル コードでは、app_1 が Foo.A を受信すると、Bar.Alpha で応答する必要があり、その逆も同様です)。
前もって感謝します!