转载

EnumSet 源码简单分析

EnumSet 的内部基本使用如下:

EnumSet<Frult> set = EnumSet.of(Frult.A, Frult.C, Frult.E); 

为什么使用 EnumSet 可以参考 effective-java。

简单看 EnumSet 类声明:

public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>     implements Cloneable, java.io.Serializable {     /**      * The class of all the elements of this set.      */     final Class<E> elementType;      /**      * All of the values comprising T.  (Cached for performance.)      */     final Enum<?>[] universe;      private static Enum<?>[] ZERO_LENGTH_ENUM_ARRAY = new Enum<?>[0];   public static <E extends Enum<E>> EnumSet<E> of(E e) {         EnumSet<E> result = noneOf(e.getDeclaringClass());         result.add(e);         return result;     }     public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {         Enum<?>[] universe = getUniverse(elementType);         if (universe == null)             throw new ClassCastException(elementType + " not an enum");          if (universe.length <= 64)             return new RegularEnumSet<>(elementType, universe);         else             return new JumboEnumSet<>(elementType, universe);     } } 

两个属性,elementType 存放枚举类型的 class,universe 是所有枚举的数组。

在 noneOf 方法当中,创建具体的 Enum 实现实例,如果 Enum 的长度大于了 64 创建 JumboEnumSet,小于等于 64 创建 RegularEnumSet。

只分析 RegularEnumSet 的情况:

class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> {     private static final long serialVersionUID = 3411599620347842686L;      private long elements = 0L;   public int size() {         return Long.bitCount(elements);     }      public boolean isEmpty() {         return elements == 0;     }      public boolean add(E e) {         typeCheck(e);//检查 Enum 的类型是否符合          long oldElements = elements;         elements |= (1L << ((Enum<?>)e).ordinal());         return elements != oldElements;     } } 

RegularEnumSet 里面就是用了一个 long 型的 elements 来存放,因为 long 是 8 个字节,一共 64 bit。并且每个枚举的元素都有 ordinal 属性,只要添加进来就根据 ordinal 来或运算就可以了。

size 方法就是看指定 long 值的二进制补码表示形式中的 1 位的数量。

下面代码是 RegularEnumSet 的迭代器实现方式:

private class EnumSetIterator<E extends Enum<E>> implements Iterator<E> {         long unseen;         long lastReturned = 0;          EnumSetIterator() {             unseen = elements;         }          public boolean hasNext() {             return unseen != 0;         }          @SuppressWarnings("unchecked")         public E next() {             if (unseen == 0)                 throw new NoSuchElementException();             lastReturned = unseen & -unseen;             unseen -= lastReturned;             return (E) universe[Long.numberOfTrailingZeros(lastReturned)];         }          public void remove() {             if (lastReturned == 0)                 throw new IllegalStateException();             elements &= ~lastReturned;             lastReturned = 0;         }     } 

迭代器 next 方法,就是从最低位取出元素,并且返回。

详细的方式就是,unseen 与运算 unseen 的相反数。结果就是每次都会把最后位是 1 的值取到,然后在通过 Long.numberOfTrailingZeros 转换成 2 的幂次数,从数组当中取到枚举元素。

最后就是那这个 lastReturned 在 unseen 当中减掉。

其他的不分析,主要是位运算,以及2进展补码的精妙之处,虽然还没搞清除为什么可以这样。。。。

以后在研究为何如此精妙。

—EOF—

原文  http://renchx.com/enumset
正文到此结束
Loading...