打字猴:1.700446613e+09
1700446613
1700446614 我们知道枚举项的排序值ordinal是从0、1、2……依次递增的,没有重号,没有跳号,RegularEnumSet就是利用这一点把每个枚举项的ordinal映射到一个long类型的每个位上的,注意看addAll方法的elments元素,它使用了无符号右移操作,并且操作数是负值,位移也是负值,这表示是负数(符号位是1)的“无符号左移”:符号位为0,并补充低位,简单地说,Java把一个不多于64个枚举项的枚举映射到了一个long类型变量上。这才是EnumSet处理的重点,其他的size方法、constains方法等都是根据elements计算出来的。想想看,一个long类型的数字包含了所有的枚举项,其效率和性能肯定是非常优秀的。
1700446615
1700446616 我们知道long类型是64位的,所以RegularEnumSet类型也就只能负责枚举项数量不大于64的枚举(这也是我们以64来举例,而不以128或512举例的原因),大于64则由JumboEnumSet处理,我们看它是怎么处理的:
1700446617
1700446618 class JumboEnumSet<E extends Enum<E>>extends EnumSet<E>{
1700446619
1700446620 //映射所有的枚举项
1700446621
1700446622 private long elements[];
1700446623
1700446624 //构造函数
1700446625
1700446626 JumboEnumSet(Class<E>elementType, Enum[]universe){
1700446627
1700446628 super(elementType, universe);
1700446629
1700446630 //默认长度是枚举项数量除以64再加1
1700446631
1700446632 elements=new long[(universe.length+63)>>>6];
1700446633
1700446634 }
1700446635
1700446636 void addAll(){
1700446637
1700446638 //elements中每个元素表示64个枚举项
1700446639
1700446640 for(int i=0;i<elements.length;i++)
1700446641
1700446642 elements[i]=-1;
1700446643
1700446644 elements[elements.length-1]>>>=-universe.length;
1700446645
1700446646 size=universe.length;
1700446647
1700446648 }
1700446649
1700446650 }
1700446651
1700446652 JumboEnumSet类把枚举项按照64个元素一组拆分成了多组,每组都映射到一个long类型的数字上,然后该数组再放置到elements数组中。简单来说JumboEnumSet类的原理与RegularEnumSet相似,只是JumboEnumSet使用了long数组容纳更多的枚举项。
1700446653
1700446654 不过,你会不会觉得这两段程序看着很让人郁闷呢?其实这是因为我们在开发中很少用到位移操作。读者可以这样理解,RegularEnumSet是把每个枚举项编码映射到一个long类型数字的每个位上,JumboEnumSet是先按照64个一组进行拆分,然后每个组再映射到一个long类型数字的每个位上,从这里我们也可以看出数字编码的奥秘!
1700446655
1700446656 从以上的分析可以看出,EnumSet提供的两个实现都是基本的数字类型操作,其性能肯定比其他的Set类型要好很多,特别是Enum的数量少于64的时候,那简直就是飞一般的速度。
1700446657
1700446658 注意 枚举项数量不要超过64,否则建议拆分。
1700446659
1700446660
1700446661
1700446662
[ 上一页 ]  [ :1.700446613e+09 ]  [ 下一页 ]