• Java EnumSet工作原理初窥


      EnumSet是Java枚举类型的泛型容器,Java既然有了SortedSet、TreeSet、HashSet等容器,为何还要多一个EnumSet<T>呢?答案肯定是EnumSet有一定的特性,举个例子,EnumSet的速度很快。其他特性就不一一列举了,毕竟本文的内容不是介绍EnumSet的特性。

      首先以事实说话,存在这样一个EnumSet,它有50个枚举值T0~T49,将50个值插入到容器(HashSet、EnumSet)中,为一个操作,将50个枚举值移出做为第二个操作。把第一个和第二个操作执行的总时间设定为一个周期,拿HashSet操作的一个周期和EnumSet的一个周期做比较自然没什么意义,所以我们用50个周期的和做为比较,HashSet耗费9ms,EnumSet耗费4ms(这个结果只说明同样的操作EnumSet比HashSet更快,不做为其他参考依据,因为这个时间不是线程独占时间)。以下是代码和结果:

    public class EnumSetTest{
        
        private static EnumTest[] enumTestArr = EnumTest.values();
    
        public static void main(String[] args) {
            Set set = new HashSet<EnumTest>();
            int i = 0;
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
            System.out.println("HashSet...Begin " + df.format(new Date()));
            while (i <= 1000) {
                addEnumerate(set);
                removeEnumerate(set);
                i++;
            }
            System.out.println("HashSet...End  " + df.format(new Date()));
    
            EnumSet<EnumTest> enumSet = EnumSet.noneOf(EnumTest.class);
            i = 0;
            System.out.println("EnumSet...Begin " + df.format(new Date()));
            while (i <= 1000) {
                addEnumerate(enumSet);
                removeEnumerate(enumSet);
                i++;
            }
            System.out.println("EnumSet...End " + df.format(new Date()));
        }
        /*
        * HashSet...Begin 2015-01-03 21:11:51.579
        * HashSet...End  2015-01-03 21:11:51.588
        * EnumSet...Begin 2015-01-03 21:11:51.589
        * EnumSet...End 2015-01-03 21:11:51.593
        * */
    
        private static void addEnumerate(Set set) {
            for (EnumTest t : enumTestArr) {
                set.add(t);
            }
        }
    
        private static void removeEnumerate(Set set) {
            for (EnumTest t : enumTestArr) {
                set.remove(t);
            }
        }
    }

    那为什么EnumSet比较快呢,EnumSet是一个抽象方法,本次测试是用到的EnumSet的实现RegularEnumSet,RegularEnumSet add方法的源码如下:

        public boolean add(E e) {
            typeCheck(e);
    
            long oldElements = elements;
            elements |= (1L << ((Enum)e).ordinal());
            return elements != oldElements;
        

    RegularEnumSet的源码

    从Add方法的源码可以看出add方法实际只是对长整型数据element做了一个操作,也就是说EnumSet实际上将枚举值保存在一个长整型数据上。没个枚举值占用一bit。每次添加做的主要操作是1、类型检查 2、 添加枚举值 3、判断枚举值是否已经添加过了。 

    现在模拟一个场景来说明EnumSet工作原理。新建一个EnumSet(Set1),并向Set1中添加EnumTest.T3(ordinal:3),代码如下

            EnumSet<EnumTest> set1 = EnumSet.noneOf(EnumTest.class);
            set1.add(EnumTest.T3);

    element本来有64个bit,这里就简略画了。这里有一个问题,就是枚举值的个数超过64个怎么办?超过64个了就用EnumSet的另一个实现JumboEnumSet。

    本文到此就结束了,至于JumboEnumSet的工作原理和RegularEnumSet其他方法的工作原理请自行探索吧。所有源码都可以在http://grepcode.com/ 找到。

  • 相关阅读:
    一步步学习微软InfoPath2010和SP2010--第十一章节--创建批准流程(7)--approval节
    一步步学习微软InfoPath2010和SP2010--第十一章节--创建批准流程(6)--表单加载规则
    一步步学习微软InfoPath2010和SP2010--第十一章节--创建批准流程(5)--状态域
    一步步学习微软InfoPath2010和SP2010--第十一章节--创建批准流程(4)--审批域
    一步步学习微软InfoPath2010和SP2010--第十一章节--创建批准流程(3)--表单视图
    SharePoint Designer 2010 安装教程
    解耦合是架构可伸缩的必要前提
    如何使用新东西
    学习开源组件之前先有平台或者先有环境再说
    沟通的技巧
  • 原文地址:https://www.cnblogs.com/accessking/p/4200000.html
Copyright © 2020-2023  润新知