我有一个类似下面的枚举,但是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
获取Baz.something
的对面对象。这有可能的解决方法吗?在此示例中,可能会在yang
和bad
之前定义yin
和good
的空占位符?
答案 0 :(得分:11)
使用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。
答案 1 :(得分:9)
您可以尝试以下方式:
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。
答案 2 :(得分:2)
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);
}
}
答案 3 :(得分: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");
}
}
}
}
答案 4 :(得分: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);
}
}
答案 5 :(得分:0)
另一种选择:)使用地图。它非常冗长,但是这样你就可以只定义每对,推断出另一个方向。
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 的第二个例子。
答案 6 :(得分: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);
}
}
答案 7 :(得分:0)
多年以后,最短且最苛刻的解决方案
public enum Baz {
YIN, // Use uppercase for enum names!
YANG,
GOOD,
EVIL;
public Baz opposite() {
return values()[ordinal() ^ 1];
}
}
它依赖于每个成员具有相反的假设,并且它们成对排列。它希望通过一种方法替换该字段,JVM将优化整个开销。这在桌面上是合理的,在Android上不太合理。
为了消除开销,我可以在这里使用静态初始化器和许多其他解决方案。