代码之家  ›  专栏  ›  技术社区  ›  Miles D

在Java中从EnumSet获取值

  •  7
  • Miles D  · 技术社区  · 17 年前

    如果你使用 EnumSet 为了存储传统的二进制值(1,2,4等),当少于64个项目时,我相信这是作为位向量存储的,并且有效地表示为长。有没有一种简单的方法可以得到这个长的值。我想要一种快速简单的方法将集合的内容存储在文件或数据库中。

    如果我以旧的方式做这件事,我只会使用一个长,然后自己做一点,尽管存在所有类型安全等问题。

    7 回复  |  直到 17 年前
        1
  •  6
  •   Jon Skeet    17 年前

    据我所知,这还没有曝光。你基本上可以自己重写它——看看EnumSet的代码来了解代码——但很遗憾,没有更好的方法来理解它:(

        2
  •  5
  •   Dave Ray    17 年前

    我认为这不能以通用的方式完成。转换为long非常容易:

    public static <T extends Enum<T>> long enumSetToLong(EnumSet<T> set)
    {
        long r = 0;
        for(T value : set)
        {
            r |= 1L << value.ordinal();
        }
        return r;
    }
    

    我不知道如何才能从long back转换为EnumSet。据我所知,没有办法(除了反射)获取枚举的值数组来进行查找。你必须在每个枚举的基础上做这件事。

    我认为序列化是应该走的路。仅仅序列化为long更容易受到版本错误的影响,或者由于重新排列枚举中的常量而导致的错误。

        3
  •  2
  •   Claude Martin    12 年前

    如果用枚举的类添加参数,这是可能的。将枚举集转换为字节的示例:

    public static <T extends Enum<T>, U extends Enum<?>> byte toByte(EnumSet<T> set, Class<U> type) {
      byte b = 0;
    
      if(type.getEnumConstants().length > 8) {
        throw new RuntimeException("enum set doesn't fit in one byte");
      }
    
      for(Enum<?> e: type.getEnumConstants()) {
        if(set.contains(e)) {
          b |= 1 << e.ordinal();
        }
      }
    
      return b;
    }
    
    public static <E extends Enum<E>> EnumSet<E> toSet(byte b, Class<E> type) {
      E[] enums = type.getEnumConstants();
      EnumSet<E> enumSet = EnumSet.noneOf(type);
    
      for(int bit = 0; bit < 8; bit++) {
        if((b & 1 << bit) > 0) {
          enumSet.add(enums[bit]);
        }
      }
    
      return enumSet;
    }
    
        4
  •  1
  •   Michael Myers KitsuneYMG    17 年前

    正如Jon Skeet所提到的,这些信息没有公开。但Dave Ray展示了如何轻松计算。 我制作了一个库,使这种转换变得简单得多。如果你使用“long”,它还会检查元素是否真的不超过64个。我必须创建一个新的数据类型,但它可以像BitSet或EnumSet一样使用。请注意,这需要Java 8或更高版本,因为它使用默认实现的接口。

    以下是链接: http://claude-martin.ch/enumbitset/

    例子:

      static enum MyEnum implements EnumBitSetHelper<MyEnum> { A, B, C }
      public static void main(final String[] args) {
        final EnumBitSet<MyEnum> set = EnumBitSet.of(MyEnum.A, MyEnum.C);
        long bitmask = set.toLong(); // = 3
      }
    
        5
  •  1
  •   Christian    11 年前

    EnumSet 实施 Serializable ,所以你可以用 ObjectOutputStream .

        6
  •  0
  •   Tom Hawtin - tackline    17 年前

    EnumSet的(典型的-不是强制的)实现使用枚举值的序号。你不应该假设序数总是保持不变。因此,如果你想使用序数有效地存储枚举集,你还应该存储一个从枚举名到序数的映射(可能存储为枚举名序列)。

    EnumSet本身似乎没有很好的序列化形式。它只是转储了一个枚举。其主体将被转录为一系列整数对象引用,而不是位集。

        7
  •  0
  •   Alex Kevin Panko    12 年前

    BitSet 在这种情况下可能很有用,因为它提供了与字节数组之间的转换。您可能仍需要申报 enum 具有显式值(1,2,3...) 位集合 猥亵。与总是64位的long不同, 位集合 似乎不允许限制其长度(例如64位)。