¿Hay alguna forma de evitar los problemas de carga de clases causados por tener dos enumeraciones que se referencian entre sí?Java Enums: dos tipos de enumeración, cada uno con referencias el uno al otro?
que tienen dos juegos de enumeraciones, Foo y Bar, que se define como tal:
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);
}
}
}
El código anterior produce como salida:
A bar Alpha
B bar Delta
C bar Alpha
Alpha foo null
Beta foo null
Delta foo null
entiendo por qué sucede - la JVM se inicia la carga de clase Foo; ve el Bar.Alpha en el constructor de Foo.A, por lo que comienza la carga de clases en Bar. Ve la referencia de Foo.A en la llamada al constructor de Bar.Alpha, pero (dado que todavía estamos en el constructor de Foo.A) Foo.A es nulo en este punto, por lo que el constructor de Bar.Alpha pasa un nulo. Si invierto los dos bucles de for (o de otro modo referencia a Bar antes de Foo), la salida cambia para que los valores de Bar sean todos correctos, pero los valores de Foo no lo son.
¿Hay alguna forma de evitar esto? Sé que puedo crear un Mapa estático y un Mapa estático en una 3ra clase, pero eso me parece bastante hackoso. También podría hacer los métodos Foo.getBar() y Bar.getFoo() que hacen referencia al mapa externo, por lo que ni siquiera cambiaría mi interfaz (las clases reales que tengo usan inspectores en lugar de campos públicos), pero todavía se siente tipo de sucio para mí.
(La razón por la que hago esto en mi sistema real: Foo y Bar representan tipos de mensajes que se envían 2 aplicaciones; los campos Foo.b y Bar.f representan el tipo de respuesta esperado para un mensaje determinado - entonces en mi código de muestra, cuando app_1 recibe un Foo.A, necesita responder con una barra.Alpha y viceversa.)
¡Gracias de antemano!
Me parece una complicación excesiva. La respuesta de @weiji es mucho más limpia, IMO. ¿Por qué es mejor este enfoque (dijiste "el mejor")? –
@NoamNelke Ya he votado el enfoque de weiji, que es muy interesante. A pesar de que personalmente creo que es mucho mejor de la manera que lo he recomendado porque la referencia cíclica está dentro de su enumeración, una gran diferencia entre nuestras respuestas es que la mía también le permitirá hacer cualquier lógica de tiempo de ejecución antes de regresar, una vez que sea necesaria, por ejemplo: 'public Bar getBar (boolean nullIfAlpha) {return nullIfAlpha? null: Bar.Alpha; } ' De todos modos, he editado mi respuesta a "uno de los mejores", ya que puede estar basada en opiniones. ¡Gracias por su respuesta! – falsarella