枚举类的学习
我一直不知道枚举有数量的差别,64个以下(包括)的的枚举是使用了RegularEnumSet,64个以上的使用了JumboEnumSet。最近看编写高质量代码这本书才发现枚举是有数量的限制,不过其实一般的项目还真用不到一个枚举类里面放这么多的枚举数量,不过既然学习了我就随便把它的源码拿出来看看吧,也弥补一下自己确实在枚举这一块的不足。
原谅我见识少,我竟然不知道有EnumMap和EnumSet枚举类的集合,这种时候就是学习的机会了。先看一下这个2个集合类的定义:
public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements java.io.Serializable, Cloneable
我擦,泛型,继承,实现全都有了,不过也就是一句话,key是枚举类的Map,666.
public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E> implements Cloneable, java.io.Serializable
两兄弟或两姐妹(也有可能是两兄妹,不过这个不重要)一样是泛型,继承,实现都有了,这个就是值是泛型的set。感觉好像差不多啊,一看就是一个模子造出来的。。。。。。。
滚犊子,不要扯那么多,我们是来学习的。对对对,学习学习。我们主要看一下EnumSet的allOf和noneOf方法,allOf方法:
public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) { EnumSet<E> result = noneOf(elementType); result.addAll(); return result; }
没有发现什么诡异的地方呀,你丫的又在扯犊子吧。一看你就不懂Java代码的主,我给你解释一下,这个方法是传入一个枚举类,none方法把枚举类转换为一个EnumSet<E>,然后在addAll(),然后在返回结果出去。我们看一下allOf方法:
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); }
当当当,出现了64了,把枚举枚举类转换为数组,然后判断数组的大小是否小于等于64,如果是的话就使用RegularEnumSet类,大于的话就使用JumboEnumSet。这2个有什么不同呢,这就有点懵逼的感觉,只能在深入去看看了。先看JumboEnumSet的addAll()方法:
private long elements[]; JumboEnumSet(Class<E>elementType, Enum<?>[] universe) { super(elementType, universe); elements = new long[(universe.length + 63) >>> 6]; } void addAll() { for (int i = 0; i < elements.length; i++) elements[i] = -1; elements[elements.length - 1] >>>= -universe.length; size = universe.length; }
Java把多于64的枚举一组扯分成了多组,每一组都映射到一个long类型的数字上,然后该数组再放置到elements数组中。long数组可以容纳更多的枚举。
RegularEnumSet的addAll():
private long elements = 0L;// 记录所有枚举排序号,注意是long型 RegularEnumSet(Class<E>elementType, Enum<?>[] universe) {//构造 super(elementType, universe); } void addAll() {//加入所有类型 if (universe.length != 0) elements = -1L >>> -universe.length; }
小于等于64个的Java利用了枚举的排序值没有重号和跳号的特点,把每个枚举的排序号映射到一个long类型的每个位上,把枚举类映射到一个long类型的变量上。两者一对比就知道就知道那个性能优了,一个数组一个long类型。所以建议不要使用超过64个枚举的枚举类。