Java enum - cannot refer to a field until it is defined

I have an enumeration similar to the one below, but the eclipse says there are errors in the first definition of each opposite pair.

public enum Baz{ yin(yang), //Cannot reference a field before it is defined yang(yin), good(evil), //Cannot reference a field before it is defined evil(good); public final Baz opposite; Baz(Baz opposite){ this.opposite = opposite; } } 

I want to execute Baz.something.opposite to get the opposite Baz.something object. Is there a possible workaround for this? Maybe the empty placeholder for yang and bad to yin and good defined in this example?

+7
source share
8 answers

You can try something like:

 public enum Baz{ yin("yang"), yang("yin"), good("evil"), evil("good"); private String opposite; Baz(String opposite){ this.opposite = opposite; } public Baz getOpposite(){ return Baz.valueOf(opposite); } } 

and then refer to it as

 Baz.something.getOpposite() 

This should do what you want to do by looking at the enumeration value with a string representation. I don’t think you can make it work with a recursive link to Baz.

+9
source

With the switch statement:

 public enum Baz{ yin, yang, good, evil; public Baz getOpposite() { switch (this) { case yin: return yang; case yang: return yin; case good: return evil; case evil: return good; } throw new AssertionError(); } 

Or delayed initialization:

 public enum Baz{ yin, yang, good, evil; public Baz opposite; static { yin.opposite = yang; yang.opposite = yin; good.opposite = evil; evil.opposite = good; } } 

You might want to make the volatile field private and provide a getter.

+11
source

What about EnumMap?

 public enum Baz { yin, yang, good, evil; private static final Map<Baz, Baz> opposites = new EnumMap<Baz, Baz>(Baz.class); static { opposites.put(yin, yang); opposites.put(yang, yin); opposites.put(good, evil); opposites.put(evil, good); } public Baz getOpposite() { return opposites.get(this); } } 
+2
source

You can also use abstract methods for delay, which have the advantages of type safety over the accepted answer.

 public enum Baz { yin(new OppositeHolder() { @Override protected Baz getOpposite() { return yang; } }), yang(new OppositeHolder() { @Override protected Baz getOpposite() { return yin; } }), good(new OppositeHolder() { @Override protected Baz getOpposite() { return evil; } }), evil(new OppositeHolder() { @Override protected Baz getOpposite() { return good; } }); private final OppositeHolder oppositeHolder; private Baz(OppositeHolder oppositeHolder) { this.oppositeHolder = oppositeHolder; } protected Baz getOpposite() { return oppositeHolder.getOpposite(); } private abstract static class OppositeHolder { protected abstract Baz getOpposite(); } } 

And the test code, because I need it ....

 import org.junit.Test; import static org.junit.Assert.fail; public class BazTest { @Test public void doTest() { for (Baz baz : Baz.values()) { System.out.println("Baz " + baz + " has opposite: " + baz.getOpposite()); if (baz.getOpposite() == null) { fail("Opposite is null"); } } } } 
+2
source

And one more possible implementation (similar to some other solutions, but with HashMap).

 import java.util.Map; import java.util.HashMap; public enum Baz { yin, yang, good, evil; private static Map<Baz, Baz> opposites = new HashMap<Baz, Baz>(); static { opposites.put(yin, yang); opposites.put(yang, yin); opposites.put(good, evil); opposites.put(evil, good); } public Baz getOpposite() { return opposites.get(this); } } 
0
source

Another alternative :) using the map. This is pretty verbose, but this way you can identify each pair only once , another direction will be drawn.

 enum Baz { YIN, YANG, GOOD, EVIL; private static final Map<Baz, Baz> opposites = new EnumMap<>(Baz.class); static { opposites.put(YIN, YANG); opposites.put(GOOD, EVIL); for (Entry<Baz, Baz> entry : opposites.entrySet()) { opposites.put(entry.getValue(), entry.getKey()); } } public Baz opposite() { return opposites.get(this); } } 

Personally, I like the second meriton example.

0
source

And then there is a complete OTT solution.

 public enum Baz { yin, yang, good, evil, right, wrong, black, white; private static class AutoReversingMap<K extends Enum<K>> extends EnumMap<K, K> { public AutoReversingMap(Class<K> keys) { super(keys); } // Make put do both the forward and the reverse. public K put(K key, K value) { super.put(key, value); super.put(value, key); // Better to return null here than a misleading real return of one of the supers. return null; } } private static final Map<Baz, Baz> opposites = new AutoReversingMap<Baz>(Baz.class); static { // Assume even and odd ones are opposites. for (int i = 0; i < Baz.values().length; i += 2) { opposites.put(Baz.values()[i], Baz.values()[i + 1]); } } public Baz getOpposite() { return opposites.get(this); } } 
0
source

In a few years, the shortest and most hacker solution

 public enum Baz { YIN, // Use uppercase for enum names! YANG, GOOD, EVIL; public Baz opposite() { return values()[ordinal() ^ 1]; } } 

He relies on the assumption that each element has an opposite and that they are arranged in pairs. It replaces the field with a method in the hope that the JVM will optimize all overhead. This is smart on the desktop, less smart on Android.

To eliminate the overhead, I could use a static initializer, like many other solutions here.

0
source

All Articles