Методы Java Enum

Я хотел бы объявить направление перечисления, которое имеет метод, который возвращает противоположное направление (следующее не является синтаксически правильным, т.е. перечисления не могут быть созданы, но это иллюстрирует мою точку). Возможно ли это на 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);
     }
}

Ответ 1

Для тех, кто заманивает сюда по названию: да, вы можете определить свои собственные методы в enum. Если вам интересно, как вызвать такой нестатический метод, вы делаете это так же, как и любой другой нестатический метод - вы вызываете его в экземпляре типа, который определяет или наследует этот метод. В случае перечислений такие экземпляры просто ENUM_CONSTANT.

Так что все, что вам нужно, это 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.


Вот немного более "хакерский" способ проиллюстрировать комментарий @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]; 
    }
}

Ответ 2

Для небольшого перечисления, подобного этому, я считаю, что наиболее читаемым решением является:

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

}

Ответ 3

Это работает:

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

Ответ 4

Создайте абстрактный метод, и каждый из ваших значений перечисления переопределит его. Поскольку вы знаете обратное, когда вы его создаете, нет необходимости динамически генерировать или создавать его.

Это не очень хорошо читается; возможно, 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();
}

Ответ 5

Да, мы делаем это все время. Вы возвращаете статический экземпляр вместо нового объекта

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

Ответ 6

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