1

我有这个枚举:

public enum Direction {
    LEFT,
    RIGHT,
    ABOVE,
    BELOW
}

我可以获取并设置一个Direction包含 2 个或更多值的变量吗,例如:

Direction fromDirection = Direction.LEFT + Direction.ABOVE

如果可能,请告诉我如何实现它。

4

5 回答 5

7

您可以使用java.util.EnumSet

final Set<Direction> northEast = EnumSet<Direction>.of(Direction.NORTH, Direction.EAST);

当然,您可以使用任何其他集合实现,但EnumSet类型被实现为位向量,非常节省空间和时间,并且可能是实现您目标的最佳内置工具。

您可能还想在检查有效组合的枚举类型中定义一个静态方法。

于 2012-08-17T05:01:24.780 回答
3

你也可以使用

private static EnumSet<Direction> someDirection = EnumSet.of(Direction.LEFT,Direction.RIGHT) ;
于 2012-08-17T05:50:51.510 回答
1

你可以通过一些黑客来实现这一点。没有比这更快的过程了。在这种情况下,EnumSet 较慢。

它基本上将枚举转换为数字,然后存储在一个整数中。整数的每个字节表示枚举是打开还是关闭。但是它有一个缺点,你不能使用大于 32 个值的枚举。实际上,如果您将其重新设计为使用值,您可以使用多达 64 个值枚举

这是我用来将多个布尔数据以单个整数大小存储到数据库中的巧妙技巧。我可以用 1 列表示所有布尔值的总和,而不是让 32 列每列代表一个布尔值。唯一的缺陷是您无法一眼就知道哪些布尔值是开/关的。

public enum ENUM
{
    AAA, SSS, DDD, FFF, GGG, HHH, JJJ, KKK, LLL, ZZZ, XXX, CCC;

    public static int add(int addTo, ENUM val)
    {
        return addTo | (1 << val.ordinal());
    }

    public static int remove(int removeFrom, ENUM val)
    {
        return removeFrom & ~(1 << val.ordinal());
    }

    public static boolean contains(int in, ENUM val)
    {
        return (in & (1 << val.ordinal())) != 0;
    }
}

public static void main(String[] args)
{
    int enums = 0;
    enums = ENUM.add(enums, ENUM.AAA);
    enums = ENUM.add(enums, ENUM.SSS);

    for (ENUM enu : ENUM.values())
        if (ENUM.contains(enums, enu))
            System.out.println(enu);
    System.out.println("Operation 2.");

    enums = ENUM.remove(enums, ENUM.AAA);
    enums = ENUM.remove(enums, ENUM.KKK);
    enums = ENUM.add(enums, ENUM.DDD);

    for (ENUM enu : ENUM.values())
        if (ENUM.contains(enums, enu))
            System.out.println(enu);
}

打印了以下结果:

AAA
SSS
Operation 2.
SSS
DDD

我将尝试以最简单的方式解释这一点。

val.ordinal()是枚举的序号。

1 << val.ordinal()将带有 X 个空格的位向左移动。(因为 1 = 00000000 00000000 00000000 00000001 在二进制中,您最多可以移动它 31 次)基本上枚举顺序是整数中的位顺序。如果枚举的顺序是 5,那么它将是 1 << 5,这意味着我们将二进制中的 1 向左移动 5 次。结果为 00000000 00000000 00000000 00100000。

结果 =添加到 | enumNum这将检查枚举位的位置并将其设置为结果整数中的 1。因此,如果 enumNum 为 00000000 00000000 00000000 00100000 并且结果(addTo)当前为 00000000 00000000 00000000 00000001,它将变为 00000000 00000000 00000000 0010。

result = removeFrom & ~enumNum首先,' ~ ' 反转位状态。“ ”检查所有位并将其设置为0,除非两个整数的当前位为1.所以让我们参见0000000000000000 00000000 00000000000000000000000000000000000000 00000001,因为唯一的一对 1 是最右边的一对。

result & enumNum正如我上面所说,所有位都变为 0,除非有一对 1。00000000 00000000 00000000 00000001 & 00000000 00000000 00000000 00100000. 这里没有一对 1,所以看起来结果是=0。如果我们将当前结果设置为 00000000 00000000 00000000 00100001 那么我们 & 00000000 00000000 00000000 00100000 我们将得到 00000000 00000000 00000000 00100000 作为最终结果。第 5 位对是一对 1,这就是它保留的原因。返回的数字是 2^5=32,即!= 0

有关按位运算如何工作的更多详细信息,请查看此处

于 2014-01-13T04:51:06.150 回答
0

不,您不能将值设置为枚举。它们是常量,每个常量都是Enum 类型的实例。

于 2012-08-17T04:53:49.750 回答
0

我可以获取并设置包含 2 个或更多值的方向变量吗

您已经将类型声明Direction为枚举,如果您再次尝试将其声明为某个变量,则会导致变量重定义错误。

枚举也是常数,以后不能重置那里的值。

于 2012-08-17T04:54:13.850 回答