1,储存方式
public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
implements Cloneable, java.io.Serializable{
final Class<E> elementType;
final Enum[] universe;
private static Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0];
EnumSet(Class<E>elementType, Enum[] universe) {
this.elementType = elementType;
this.universe = universe;
}
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);
}
private static <E extends Enum<E>> E[] getUniverse(Class<E> elementType) {
return java.lang.JavaLangAccess.getEnumConstantsShared(elementType);
}
}
// RegularEnumSet
class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> {
private long elements = 0L;
RegularEnumSet(Class<E>elementType, Enum[] universe) {
super(elementType, universe);
}
}
// JumboEnumSet
class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> {
private long elements[];
private int size = 0;
JumboEnumSet(Class<E>elementType, Enum[] universe) {
super(elementType, universe);
elements = new long[(universe.length + 63) >>> 6];
}
}
1)从noneOf()出发可以看到,储存数据的结构为:final Enum[] universe,而且,全局中仅有构造函数对该数据赋值了,因此:储存数据在构造函数就初始化完成
2)它依据初始化的Enum的大小,分别实现了两个实现类,本文仅分析RegularEnumSet,读者可以自己分析另一个
2,自增方式
public boolean add(E e) {
typeCheck(e);
long oldElements = elements;
elements |= (1L << ((Enum)e).ordinal());
return elements != oldElements;
}
1)位运算,“(1L << ((Enum)e).ordinal())” 作用:获取一个 000..010..00的二进制,1的位置就是位移的数量
“elements |=” 作用:对所有位数进行或运算,因此,整个位运算就是将 指定位数的数据变成 1
2)通过1)的分析,可以看出它增加了一个数,就是将指定位数添加1。也就是说,它是使用0和1来表示,某个元素是否存在。
以上便是,EnumSet使用“位向量”来标识数据的实现方式。而Long的位数为64,因此它最多表示64个。
3,查询数据
仅提供遍历获取的方式
4,获取整体大小
public int size() {
return Long.bitCount(elements);
}
EnumSet使用“位向量”储存数据,因此只需要统计它"1"的个数,也就是它的size
EnumSet在构造函数就获取了所有数据,并储存在一个定长数组中,这很适合储存Enum的数据。
同样使用定长数组储存数据的还有:EnumMap