Подтвердить что ты не робот

Как написать родовой ротатор Java enum?

Как создать общий ротатор enum? В этом примере это была бы общая версия next().

    public class TestEnum
    {
        enum Temperature { hot, cold };

        public static void main(String[] args)
        {
            Temperature t = Temperature.hot;
            Temperature t2 = next(t);
        }

        static Temperature next(Temperature t)
        {
            if (t.ordinal() == Temperature.values().length - 1)
                return Temperature.values()[0];
            else
                return Temperature.values()[t.ordinal() + 1];
        }
    }

Изменить: В комментариях @irreputable предлагает превосходное решение. irreputable, если вы разместите его в качестве ответа, я его выберу. Вы можете сэкономить время, скопировав этот ответ.

static <T extends Enum<T>> T next(T t)
{
    int index = t.ordinal();
    @SuppressWarnings("unchecked")
    Enum<T>[] constants = t.getClass().getEnumConstants();
    if (index == constants.length - 1)
    {
        @SuppressWarnings("unchecked")
        T result = (T)constants[0];
        return result;
    }
    else
    {
        @SuppressWarnings("unchecked")
        T result = (T)constants[index + 1];
        return result;
    }
}
4b9b3361

Ответ 1

Try:

public class Test {

    enum Temperature { hot, cold };

        public static void main(String[] args) throws Exception
        {
            Temperature t = Temperature.hot;
            Temperature t2 = next(t);
            System.out.println(t2);
        }

        static <T extends Enum> T next(T t) throws Exception
        {
            Method values = t.getClass().getMethod("values");
            if (t.ordinal() == ((T[])values.invoke(t)).length - 1)
                return ((T[])values.invoke(t))[0];
            else
                return ((T[])values.invoke(t))[t.ordinal() + 1];
        }
}

Ответ 2

ИМО, полагаясь на позицию подумать о "следующем" или "предыдущем", будет плохой идеей, так же, как плохой идеей полагаться на порядковый номер() в коде приложения. Было бы разумнее, чтобы ваше перечисление определяло, как должно происходить ротация, чтобы добавление новых членов между ними не испортило бы вещи.

Есть два решения, которые вы можете попробовать: убедитесь, что каждый enum, созданный, неявно обрабатывает следующее интеллектуально, что обеспечивает большую степень гибкости или создает общую политику ротации, которая может использоваться всеми перечислениями, которые поддерживают вращение, но имеют меньшую гибкость.

Подход 1 (большая гибкость)

enum Direction1 {

    EAST() {
        @Override
        public Direction1 next(Rotation rotation) {
            return rotation == Rotation.CLOCKWISE ? SOUTH : NORTH;
        }
    },
    WEST() {
        @Override
        public Direction1 next(Rotation rotation) {
            return rotation == Rotation.CLOCKWISE ? NORTH : SOUTH;
        }
    },
    SOUTH() {
        @Override
        public Direction1 next(Rotation rotation) {
            return rotation == Rotation.CLOCKWISE ? WEST : EAST;
        }
    },
    NORTH() {
        @Override
        public Direction1 next(Rotation rotation) {
            return rotation == Rotation.CLOCKWISE ? EAST : WEST;
        }
    };

    abstract Direction1 next(Rotation rotation);

    static enum Rotation {
        CLOCKWISE, ANTICLOCKWISE
    };

}

Подход 2, более общий, менее гибкий

interface Rotatable {
    // now it would be difficult to make next() method take a rotation
    Rotatable next();
}

enum Direction2 implements Rotatable {

    // assume clockwise rotation

    EAST() {
        @Override
        public Direction2 next() {
            return SOUTH;
        }
    },
    WEST() {
        @Override
        public Direction2 next() {
            return NORTH;
        }
    },
    SOUTH() {
        @Override
        public Direction2 next() {
            return WEST;
        }
    },
    NORTH() {
        @Override
        public Direction2 next() {
            return EAST;
        }
    };

}

Ответ 3

Использование интерфейса:

public interface EnumInterface {
    public EnumInterface[] values1();
    public int ordinal1();
}   

enum Temperature implements EnumInterface {
    HOT,
    COLD;

    public EnumInterface[] values1() {
        return values();
    }

    public int ordinal1() {
        return ordinal();
    }
}

static <T extends EnumInterface> T next(T t) {      
    if (t.ordinal1() == t.values1().length - 1)
        return (T) t.values1()[0];
    else
        return (T) t.values1()[t.ordinal1() + 1];
} 

public static void main(String[] args) {
    Temperature t = Temperature.HOT;
    Temperature t2 = next(t);
    System.out.println(t2);
}

Ответ 4

Это не прямой ответ на вопрос, а другой подход к тому, что вы пытаетесь сделать.

public interface<T extends Enum<T>> NextEnum {
    T next();
}

public enum Temperature implements NextEnum<Temperature> {
    hot, cold;

    public Temperature next() {
        if (ordinal() == Temperature.values().length - 1)
            return Temperature.values()[0];
        else
            return Temperature.values()[ordinal() + 1];
    }
}

Для всех перечислений, которые реализуют NextEnum, вы можете использовать метод next(). Например:

Temperature.hot.next();

Ответ 5

Я считаю, что использование порядковых значений всегда является хрупким подходом, поскольку оно будет полагаться на позицию, либо используйте values(), либо class.getEnumConstants().

Ответ 6

public <T extends Enum<T>> T rotate(T current, int increment) {
  T[] values = current.getDeclaringClass().getEnumConstants();
  int i = current.ordinal() + increment;
  while (i<0) i+= values.length; 
  return values[i%values.length];
}

Temperature next = rotate(hot, 1);
Temperature prev = rotate(hot, -1);
Temperature nextNext = rotate(hot, 2);