Есть ли способ обойти проблемы загрузки класса, вызванные наличием двух перечислений, которые ссылаются друг на друга?
У меня есть два набора перечислений, Foo и Bar, определенные так:
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; он видит Bar.Alpha в Foo.A-конструкторе, поэтому он запускает classloading Bar. Он видит ссылку Foo.A в вызове конструктора Bar.Alpha, но (поскольку мы все еще находимся в Foo.A-конструкторе) Foo.A на данный момент равно null, поэтому конструктор Bar.Alpha получает значение null. Если я отменил два для циклов (или в противном случае ссылку Bar перед Foo), выход изменится так, чтобы значения Bar были правильными, но значения Foo не являются.
Есть ли способ обойти это? Я знаю, что могу создать статическую карту и статическую карту в 3-м классе, но для меня это довольно грустно. Я мог бы также создавать методы Foo.getBar() и Bar.getFoo(), которые относятся к внешней карте, поэтому он даже не изменит мой интерфейс (фактические классы, в которых я использую инспекторов вместо публичных полей), но он все еще чувствует вроде нечистого для меня.
(Причина, по которой я делаю это в своей реальной системе: Foo и Bar представляют собой типы сообщений, которые 2 приложения отправляют друг другу, поля Foo.b и Bar.f представляют ожидаемый тип ответа для данного сообщения - поэтому в моем примере кода, когда app_1 получает Foo.A, ему нужно ответить с помощью Bar.Alpha и наоборот.)
Спасибо заранее!