Existe-t-il un moyen de contourner les problèmes de chargement de classes provoqués par l'existence de deux énumérations se référant mutuellement?Java Enums: deux types enum, contenant chacun des références les uns aux autres?
J'ai deux ensembles de énumérations, Foo et Bar, définis comme ceci:
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);
}
}
}
Le code ci-dessus produit en sortie:
A bar Alpha
B bar Delta
C bar Alpha
Alpha foo null
Beta foo null
Delta foo null
Je comprends pourquoi cela se produit - la machine virtuelle démarre classloading Foo; il voit le constructeur Bar.Alpha dans Foo.A, donc il commence à classer Bar. Il voit la référence Foo.A dans l'appel au constructeur de Bar.Alpha, mais (puisque nous sommes toujours dans le constructeur de Foo.A) Foo.A est nul à ce stade, donc le constructeur de Bar.Alpha reçoit un null. Si j'inverse les deux pour les boucles (ou si je fais référence à Bar avant Foo), la sortie change pour que les valeurs de Bar soient correctes, mais pas celles de Foo.
Y at-il un moyen de contourner ce problème? Je sais que je peux créer une carte statique et une carte statique dans une 3ème classe, mais cela me semble assez hackish. Je pourrais aussi faire des méthodes Foo.getBar() et Bar.getFoo() qui se réfèrent à la carte externe, donc ça ne changerait même pas mon interface (les classes que j'ai utilisées inspecteurs au lieu des champs publics), mais ça sent toujours sorte d'impur pour moi.
(La raison pour laquelle je fais cela dans mon système actuel: Foo et Bar représentent les types de messages que 2 applications envoient les uns aux autres, les champs Foo.b et Bar.f représentent le type de réponse attendu pour un message donné - donc dans mon exemple de code, quand app_1 reçoit un Foo.A, il doit répondre avec un Bar.Alpha et vice-versa.)
Merci d'avance!
Semble à moi comme sur complication. réponse @ weiji est beaucoup plus propre, IMO. Pourquoi cette approche est-elle meilleure (vous avez dit "le meilleur")? –
@NoamNelke J'ai déjà voté pour l'approche de weiji, ce qui est très intéressant. Bien que je pense personnellement que c'est beaucoup mieux comme je l'ai recommandé car la référence cyclique est dans son énumération, une grande différence entre nos réponses est que la mienne vous permettrait également de faire une logique d'exécution avant de revenir, par exemple: 'public Bar getBar (booléen nullIfAlpha) {return nullIfAlpha? null: Bar.Alpha; } '. Quoi qu'il en soit, j'ai modifié ma réponse à "l'un des meilleurs", car il peut être basé sur l'opinion. Merci pour votre réponse! – falsarella