Java enum- Cannot reference a field before it is defined

匿名 (未验证) 提交于 2019-12-03 02:30:02

问题:

I have an enum like the one below, but eclipse says that 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;   } } 

What I want to accomplish is being able to use Baz.something.opposite to get the opposite object of Baz.something. Is there a possible workaround for this? Maybe an empty placeholder for yang and bad before yin and good are defined in this example?

回答1:

You could 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 reference it as

Baz.something.getOpposite() 

That should accomplish what you are looking to do by looking up the enum value by it's string representation. I don't think you can get it to work with the recursive reference to Baz.



回答2:

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 deferred 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 wish to make the mutable field private and provide a getter.



回答3:

How about an 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);   } } 


回答4:

Years later, the shortest and most hacky solution

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

It relies on the assumption that each member has an opposite and that they're arranged pairwise. It replaces the field by a method in the hope, that the JVM will optimize the whole overhead away. This is reasonable on desktop, less reasonable on Android.

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



回答5:

You can also use abstract methods to delay, which has benefits 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 test code, because I needed 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");             }         }     } } 


回答6:

And yet another possible implementation (similar to some of the other solutions, but with a 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);  }  } 


回答7:

One more alternative :) using a map. It's quite verbose, but this way you can define each pair only once, the other direction is inferred.

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 meriton's second example the best.



回答8:

And then there is the totally 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);   } } 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!