有没有办法来解决造成具有参考两个彼此枚举类加载的问题?
我有两套枚举,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启动类加载富; 它看到Bar.Alpha在Foo.A的构造函数,所以它启动类加载吧。 它认为在调用Bar.Alpha的构造函数中Foo.A参考,但(因为我们仍然在Foo.A的构造函数)Foo.A在这一点空,所以Bar.Alpha对象的构造函数传递空。 如果我扭转两个for循环(或其他参考美孚之前吧),输出的变化,使酒吧的价值观是正确的,但Foo的价值都没有。
有没有什么办法来解决这个问题? 我知道我可以创建一个静态映射,并在第三类中的静态地图,但感觉还算的hackish给我。 我也可以做Foo.getBar()和Bar.getFoo()方法引用外部地图,所以它甚至不改变我的接口(实际的课程我使用视察员,而不是公共领域),但它仍然感觉那种不洁给我。
(我在我的实际系统这样做的原因是:Foo和Bar代表类型的消息2个应用程序发送给对方;在Foo.b和Bar.f字段表示给定消息的预期响应类型 - 所以在我示例代码,当APP_1接收Foo.A,它需要与Bar.Alpha反之亦然答辩。)
提前致谢!
Answer 1:
一个最好的方法是使用枚举多态性技术 :
public class EnumTest {
public enum Foo {
A {
@Override
public Bar getBar() {
return Bar.Alpha;
}
},
B {
@Override
public Bar getBar() {
return Bar.Delta;
}
},
C {
@Override
public Bar getBar() {
return Bar.Alpha;
}
},
;
public abstract Bar getBar();
}
public enum Bar {
Alpha {
@Override
public Foo getFoo() {
return Foo.A;
}
},
Beta {
@Override
public Foo getFoo() {
return Foo.C;
}
},
Delta {
@Override
public Foo getFoo() {
return Foo.C;
}
},
;
public abstract Foo getFoo();
}
public static void main(String[] args) {
for (Foo f : Foo.values()) {
System.out.println(f + " bar " + f.getBar());
}
for (Bar b : Bar.values()) {
System.out.println(b + " foo " + b.getFoo());
}
}
}
以上代码生成你想要的输出:
A bar Alpha
B bar Delta
C bar Alpha
Alpha foo A
Beta foo C
Delta foo C
也可以看看:
Answer 2:
这个问题与其说是“两个枚举相互引用”,它更“两个枚举在它们的构造相互引用”。 这个循环引用是棘手的部分。
如何使用Foo.setResponse(Bar b)
和Bar.setResponse(Foo f)
的方法呢? 而不是在富构造设置美孚酒吧(类似一个酒吧在酒吧构造美孚),你就使用初始化的方法? 例如:
富:
public enum Foo {
A, B, C;
private void setResponse(Bar b) {
this.b = b;
}
private Bar b;
public Bar getB() {
return b;
}
static {
A.setResponse(Bar.Alpha);
B.setResponse(Bar.Delta);
C.setResponse(Bar.Alpha);
}
}
酒吧:
public enum Bar {
Alpha, Beta, Delta;
private void setResponse(Foo f) {
this.f = f;
}
private Foo f;
public Foo getF() {
return f;
}
static {
Alpha.setResponse(Foo.A);
Beta.setResponse(Foo.C);
Delta.setResponse(Foo.C);
}
}
另外,你提到Foo和酒吧有两种类型的消息。 是否可以将它们合并成一个单一的类型? 从我所看到的,在这里他们的行为是一样的。 这不固定循环逻辑,但它可能给你一些其他的洞察您的设计...
Answer 3:
因为它似乎你将是反正硬编码,为什么不能有这样的事
public static Bar responseBar(Foo f) {
switch(f) {
case A: return Bar.Alpha;
// ... etc
}
}
每个枚举? 它看起来像你必须在你的榜样一些重叠的反应,所以你甚至可以采取通过下降的情况下的优势。
编辑:
我喜欢EnumMap的汤姆的建议; 我想表现可能更快的EnumMap的,但似乎是某种有效的Java描述优雅的建筑并没有被这个特殊的问题被给予-然而,以上所提供的交换机解决方案将构建两个静态EnumMaps一个很好的方式,那么反应可能是这样的:
public static Bar response(Foo f) { return FooToBar.get(f); }
public static Foo response(Bar b) { return BarToFoo.get(b); }
Answer 4:
有趣的设计。 我看你的需要,但什么是你打算怎么办时要求稍微移动,从而使响应Foo.Epsilon,APP_1应该发送无论是Bar.Gamma或Bar.Whatsit?
你认为和丢弃hackish的解决方案(把关系到地图)似乎给你更多的灵活性,并且避免你的循环引用。 它也保持划分责任:消息类型本身不应该是负责了解他们的反应,他们应该?
Answer 5:
您可以使用EnumMap的,和枚举的一个内填充它。
private static EnumMap<Foo, LinkedList<Bar>> enumAMap;
public static void main(String[] args) throws Exception {
enumAMap = new EnumMap<Foo, LinkedList<Bar>>(Foo.class);
System.out.println(Bar.values().length); // initialize enums, prevents NPE
for (Foo a : Foo.values()) {
for (Bar b : enumAMap.get(a)) {
System.out.println(a + " -> " + b);
}
}
}
public enum Foo {
Foo1(1),
Foo2(2);
private int num;
private Foo(int num) {
this.num = num;
}
public int getNum() {
return num;
}
}
public enum Bar {
Bar1(1, Foo.Foo1),
Bar2(2, Foo.Foo1),
Bar3(3, Foo.Foo2),
Bar4(4, Foo.Foo2);
private int num;
private Foo foo;
private Bar(int num, Foo foo) {
this.num = num;
this.foo = foo;
if (!enumAMap.containsKey(foo)) {
enumAMap.put(foo, new LinkedList<Bar>());
}
enumAMap.get(foo).addLast(this);
}
public int getNum() {
return num;
}
public Foo getFoo() {
return foo;
}
}
输出:
4
Foo1 -> Bar1
Foo1 -> Bar2
Foo2 -> Bar3
Foo2 -> Bar4
文章来源: Java Enums: Two enum types, each containing references to each other?