问题描述
我有两套枚举,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);
私人酒吧(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+ fb);
}
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。如果我反转两个for循环(或者在Foo之前以其他方式引用Bar),则输出更改,以便Bar的值都正确,但Foo的值不是。
是否有什么办法解决这个问题吗?我知道我可以在第三类中创建静态地图和静态地图,但对我来说感觉相当骇人听闻。我也可以使Foo.getBar()和Bar.getFoo()方法引用外部地图,所以它甚至不会改变我的界面(实际的类我使用检查员而不是公共领域),但仍然感觉对我来说,这是一种不洁净的东西。
(我在实际系统中这样做的原因:Foo和Bar代表了两个应用程序发送给他人的消息类型; Foo.b和Bar.f字段表示给定消息的预期响应类型 - 所以在我的示例代码中,当app_1收到一个Foo.A时,它需要使用Bar.Alpha进行回复,反之亦然。)
提前感谢!
最好的方法之一是使用枚举多态技术:
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。一个;
}
},
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());
}
(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
另请参见:
Is there a way to get around the class-loading issues caused by having two enums that reference each other?
I have two sets of enumerations, Foo and Bar, defined like so:
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);
}
}
}
The above code produces as output:
A bar Alpha
B bar Delta
C bar Alpha
Alpha foo null
Beta foo null
Delta foo null
I understand why it happens - the JVM starts classloading Foo; it sees the Bar.Alpha in Foo.A's constructor, so it starts classloading Bar. It sees the Foo.A reference in the call to Bar.Alpha's constructor, but (since we're still in Foo.A's constructor) Foo.A is null at this point, so Bar.Alpha's constructor gets passed a null. If I reverse the two for loops (or otherwise reference Bar before Foo), the output changes so that Bar's values are all correct, but Foo's values are not.
Is there any way to get around this? I know I can create a static Map and a static Map in a 3rd class, but that feels fairly hackish to me. I could also make Foo.getBar() and Bar.getFoo() methods that refer to the external map, so it wouldn't even change my interface (the actual classes I have use inspectors instead of public fields), but it still feels kind of unclean to me.
(The reason I'm doing this in my actual system: Foo and Bar represent types of messages that 2 apps send to each other; the Foo.b and Bar.f fields represent the expected response type for a given message - so in my sample code, when app_1 receives a Foo.A, it needs to reply with a Bar.Alpha and vice-versa.)
Thanks in advance!
One of the best ways would be using the enum polymorphism technique:
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());
}
}
}
The above code produces the output you want:
A bar Alpha
B bar Delta
C bar Alpha
Alpha foo A
Beta foo C
Delta foo C
See also:
这篇关于Java枚举:两个枚举类型,每个包含彼此的引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!