10

我有一个像下面这样的枚举,但是 eclipse 说每个相反对的第一个定义中有错误。

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;
  }
}

我想要完成的是能够用来Baz.something.opposite获取. 有没有可能的解决方法?也许在这个例子中定义了一个空的占位符 for and before and ?Baz.somethingyangbadyingood

4

8 回答 8

14

使用 switch 语句:

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();
}

或延迟初始化:

public enum Baz{
  yin,
  yang,
  good,
  evil;

  public Baz opposite;

  static {
    yin.opposite = yang;
    yang.opposite = yin;
    good.opposite = evil;
    evil.opposite = good;
  }
}

您可能希望将可变字段设为私有并提供一个 getter。

于 2012-09-25T23:20:45.230 回答
12

您可以尝试以下方法:

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);
  }
}

然后将其引用为

Baz.something.getOpposite()

这应该通过它的字符串表示查找枚举值来完成您想要做的事情。我认为你不能让它与对 Baz 的递归引用一起工作。

于 2012-09-25T23:05:05.113 回答
4

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);
  }
}
于 2012-09-25T23:26:41.403 回答
2

您还可以使用抽象方法来延迟,这比公认的答案具有类型安全的好处。

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();
    }

}

并测试代码,因为我需要它......

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");
            }
        }
    }
}
于 2015-03-22T20:01:54.813 回答
1

另一种选择:) 使用地图。这很冗长,但这样你可以只定义每对一次,推断出另一个方向。

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);
    }
}

就个人而言,我最喜欢Meriton的第二个例子。

于 2012-09-25T23:28:58.040 回答
0

还有另一种可能的实现(类似于其他一些解决方案,但使用 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);
 }

}
于 2012-09-25T23:25:00.630 回答
0

然后是完全 OTT 解决方案。

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);
  }
}
于 2012-09-25T23:47:45.497 回答
0

多年后,最短和最 hacky 的解决方案

public enum Baz {
    YIN, // Use uppercase for enum names!
    YANG,
    GOOD,
    EVIL;

    public Baz opposite() {
        return values()[ordinal() ^ 1];
    }
}

它依赖于每个成员都有对立面并且成对排列的假设。它用一种方法替换了该字段,希望 JVM 将优化整个开销。这在桌面上是合理的,在 Android 上不太合理。

为了消除开销,我可以在这里使用静态初始化程序作为许多其他解决方案。

于 2014-05-20T08:47:35.330 回答