简体   繁体   English

如何编写通用Java枚举旋转器?

[英]How do I write a generic Java enum rotator?

How do I make a generic enum rotator? 如何制作通用枚举旋转器? It would be a generic version of next() in this example. 在这个例子中,它将是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];
        }
    }

Edit: In the comments, @irreputable suggests a superior solution. 编辑:在评论中, @irreputable提出了一个出色的解决方案。 irreputable if you post it as an answer I will select it. 如果你发布它作为答案我将选择它是irreputable You might want to save time by copying this answer. 您可能希望通过复制此答案来节省时间。

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

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

IMO, relying on position to think of "next" or "previous" would be a bad idea, just as it is a bad idea to rely on ordinal() in your application code. IMO依靠位置来思考“下一个”或“前一个”将是一个坏主意,就像在应用程序代码中依赖ordinal()一样糟糕。 It would make more sense to have your enum determine how the rotation should take place so that adding new members in between wouldn't screw up stuff. 让你的枚举确定如何进行旋转会更有意义,这样在中间添加新成员就不会搞砸了。

There are two solutions you can try out: making sure each enum created implicitly handles the next intelligently which provides for greater degree of flexibility or create a generic rotation policy which can be used by all enums which supports rotation but has less flexibility. 您可以尝试两种解决方案:确保创建的每个枚举都隐式处理下一个智能,这提供了更大程度的灵活性或创建了一个通用的轮换策略,可供所有支持轮换但灵活性较低的枚举使用。

Approach 1 (greater flexibility) 方法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
    };

}

Approach 2, more generic, less flexibility 方法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;
        }
    };

}

我相信使用序数值总是一个脆弱的方法,因为它将依赖于position,使用values()class.getEnumConstants()

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

Using an interface: 使用界面:

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

This is not a direct answer to a question but rather a different approach to what you are trying to do. 这不是问题的直接答案,而是与您尝试做的不同的方法。

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

For all enums that implement NextEnum you can use the next() method. 对于实现NextEnum所有枚举,您可以使用next()方法。 For example: 例如:

Temperature.hot.next();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM