Java枚举方法-返回相反方向的枚举


113

我想声明一个枚举Direction,它具有一个返回相反方向的方法(以下语法不正确,即,不能实例化枚举,但它说明了我的观点)。这在Java中可行吗?

这是代码:

public enum Direction {

     NORTH(1),
     SOUTH(-1),
     EAST(-2),
     WEST(2);

     Direction(int code){
          this.code=code;
     }
     protected int code;
     public int getCode() {
           return this.code;
     }
     static Direction getOppositeDirection(Direction d){
           return new Direction(d.getCode() * -1);
     }
}

只需使用一个开关。您只有4种情况。
Sotirios Delimanolis

12
顺便说一句,d.getCode() * -1==-d.getCode()
tckmn 2013年

Bloch的“ 有效的Java”的第6章(至少在2E中)可能很有趣,因此强烈建议您这样做。
jedwards

ntu.edu.sg/home/ehchua/programming/java/javaenum.html,第2.1节清楚地解释了这一概念
vikramvi

Answers:


206

对于那些按标题吸引的人:是的,您可以在枚举中定义自己的方法。如果您想知道如何调用这种非静态方法,则可以使用与其他任何非静态方法相同的方法-在定义或继承该方法的类型实例上调用它。如果是枚举,则此类实例仅为ENUM_CONSTANTs。

因此,您所需要做的就是EnumType.ENUM_CONSTANT.methodName(arguments)


现在让我们从问题回到问题。解决方案之一可能是

public enum Direction {

    NORTH, SOUTH, EAST, WEST;

    private Direction opposite;

    static {
        NORTH.opposite = SOUTH;
        SOUTH.opposite = NORTH;
        EAST.opposite = WEST;
        WEST.opposite = EAST;
    }

    public Direction getOppositeDirection() {
        return opposite;
    }

}

现在Direction.NORTH.getOppositeDirection()将返回Direction.SOUTH


这是更多@hacked的方式来说明@jedwards注释,但是它并不像第一种方法那样灵活,因为添加更多字段或更改其顺序将破坏我们的代码。

public enum Direction {
    NORTH, EAST, SOUTH, WEST;

    // cached values to avoid recreating such array each time method is called
    private static final Direction[] VALUES = values();

    public Direction getOppositeDirection() {
        return VALUES[(ordinal() + 2) % 4]; 
    }
}

3
我本来打算.values()[ordinal()]黑客攻击,但这种方法更可靠
-jedwards

但是,您如何使用它呢?这种技术叫什么?
Thufir

1
@Thufir“ 您如何使用它 ”,如果您询问方法,那么就像其他任何方法一样,您可以使用此方法在类的实例上调用它。实例Direction枚举类是NORTHEASTSOUTHWEST所以你可以使用NORTH.getOppositeDirection()它将返回SOUTH。“ 此技术叫什么? ”如果您要询问的static{...}静态初始化块,则是在首次加载类时调用代码(这是初始化静态字段的同一过程的一部分)。
Pshemo

@Pshemo,我想知道上面代码的Spring版本如何,如果需要从says属性文件中注入在静态块中设置的值。
维卡斯·普拉萨德

162

对于这样的小枚举,我发现最易读的解决方案是:

public enum Direction {

    NORTH {
        @Override
        public Direction getOppositeDirection() {
            return SOUTH;
        }
    }, 
    SOUTH {
        @Override
        public Direction getOppositeDirection() {
            return NORTH;
        }
    },
    EAST {
        @Override
        public Direction getOppositeDirection() {
            return WEST;
        }
    },
    WEST {
        @Override
        public Direction getOppositeDirection() {
            return EAST;
        }
    };


    public abstract Direction getOppositeDirection();

}

8
好想法!当您通常希望每个枚举值都具有特定的行为时,这也很好。
OferBr 2014年

28

这有效:

public enum Direction {
    NORTH, SOUTH, EAST, WEST;

    public Direction oppose() {
        switch(this) {
            case NORTH: return SOUTH;
            case SOUTH: return NORTH;
            case EAST:  return WEST;
            case WEST:  return EAST;
        }
        throw new RuntimeException("Case not implemented");
    }
}

8
与其返回null而不是抛出适当的RuntimeException的默认子句,不如表明未为新添加的方向定义相反内容的程序员错误,可能会更好。
Timothy055

1
这要求调用者处理null。它还要求维护人员确保每次添加新的Direction类型时都添加案例。请参阅Amir Afghani关于使用抽象方法的答案,该方法可以被每个枚举值覆盖,这样您就不必冒险遗漏任何方法,也不必担心处理null。
Michael Peterson

14

创建一个抽象方法,并使每个枚举值都覆盖它。由于您在创建对象时就知道相反的情况,因此无需动态生成或创建它。

但是,它的阅读效果并不理想。也许一个switch会更易于管理?

public enum Direction {
    NORTH(1) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.SOUTH;
        }
    },
    SOUTH(-1) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.NORTH;
        }
    },
    EAST(-2) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.WEST;
        }
    },
    WEST(2) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.EAST;
        }
    };

    Direction(int code){
        this.code=code;
    }
    protected int code;

    public int getCode() {
        return this.code;
    }

    public abstract Direction getOppositeDirection();
}

4

是的,我们一直都这样做。您返回一个静态实例,而不是一个新的对象

 static Direction getOppositeDirection(Direction d){
       Direction result = null;
       if (d != null){
           int newCode = -d.getCode();
           for (Direction direction : Direction.values()){
               if (d.getCode() == newCode){
                   result = direction;
               }
           }
       }
       return result;
 }

0
public enum Direction {
    NORTH, EAST, SOUTH, WEST;

    public Direction getOppositeDirection(){
        return Direction.values()[(this.ordinal() + 2) % 4];
    }
}

枚举有一个静态值方法,该方法按声明顺序返回包含枚举的所有值的数组。资源

由于NORTH获得1,EAST获得2,SOUTH获得3,WEST获得4;您可以创建一个简单的方程来得到相反的方程:

(值+ 2)%4


2
为什么这是答案?您如何期望这可以帮助将来的读者或任何与此相关的人学习而无需任何解释?
GrumpyCrouton

尽管此代码可以回答问题,但提供有关如何和/或为什么解决问题的其他上下文将提高答案的长期价值。请记住,您将来会为读者回答问题,而不仅仅是现在问的人!请编辑您的答案以添加说明,并指出适用的限制和假设。提一下为什么这个答案比其他答案更合适,这也没有什么坏处。
ItamarG3

没有注释就很难阅读代码吗?还是需要7行代码专用的javadoc?
Pregunton

1
该解决方案很脆弱,因为它取决于枚举值的顺序。如果您将顺序更改为字母顺序,那么巧妙的方程式将不再提供正确的对立面。
Josh J
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.