EnumSet源码

1、EnumSet分析

  • EnumSet是抽象类,主要通过底层的两个类进行操作

  • 内部使用位向量,表示很简洁,节省空间

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Yf7Jfno-1582708359115)(images/22.png)]

2、实现原理

采用位向量实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OmkbPteJ-1582708359116)(images/23.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kaE5NW97-1582708359117)(images/24.png)]

对象内部组成

  //表示类型信息
    final Class<E> elementType;

 //表示枚举类的所有枚举值
            //EnumSet字舍恩没有记录元素个数的变量,也没有位向量
            //它们是子类维护的
    final Enum<?>[] universe;

3、创建对象

与TreeSet/HashSet不同,EnumSet是一个抽象类,不能直接通过new创建;但是它由大量的静态方法可以创建对象

3.1、 public static <E extends Enum> EnumSet noneOf

 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");
        //小于64使用 RegularEnumSet 自了一
        if (universe.length <= 64)
            return new RegularEnumSet<>(elementType, universe);
        else
            //大于64 使用  JumboEnumSet 子类
            return new JumboEnumSet<>(elementType, universe);
    }



//RegularEnumSet构造方法
 //调用父类变量为  实例变量赋值
    RegularEnumSet(Class<E>elementType, Enum<?>[] universe) {
        super(elementType, universe);
    }




//JumboEnumSet构造方法
 JumboEnumSet(Class<E>elementType, Enum<?>[] universe) {
        super(elementType, universe);
        //根据元素根数分配足够长度的long数组
        elements = new long[(universe.length + 63) >>> 6];
    }

其他的工厂方法基本都是调用noneOf方法先构造一个集合,然后再调用添加方法

3、add方法

RegularEnumSet的add方法

public boolean add(E e) {
        typeCheck(e);
        long oldElements = elements;
        //主要代码是按位操作
        //将e元素对应的位设置为1,与现有的位变量elements相或,就表示添加了e
        elements |= (1L << ((Enum<?>)e).ordinal());
        return elements != oldElements;
    }

JumboEnumSet的add方法

ublic boolean add(E e) {
        typeCheck(e);
        //与RegularEnumSet的add方法的区别就是:
            //它先找到对应的数组位置,eOrdinal>>>6就是eOrdinal除以64
        int eOrdinal = e.ordinal();
        int eWordNum = eOrdinal >>> 6;
        //有了索引的之后,其他操作与RegularEnumSet就类似
        long oldElements = elements[eWordNum];
        elements[eWordNum] |= (1L << eOrdinal);
        boolean result = (elements[eWordNum] != oldElements);
        if (result)
            size++;
        return result;
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vm12lnd1-1582708359118)(images/25.png)]

4、remove方法

 public boolean remove(Object e) {
        if (e == null)
            return false;
        Class<?> eClass = e.getClass();
        if (eClass != elementType && eClass.getSuperclass() != elementType)
            return false;

        long oldElements = elements;
        //取反,该代码将元素e对应的位设置为0,这样就完成了删除
        elements &= ~(1L << ((Enum<?>)e).ordinal());
        return elements != oldElements;
    }

5、contains方法

 public boolean contains(Object e) {
        if (e == null)
            return false;
        Class<?> eClass = e.getClass();
        if (eClass != elementType && eClass.getSuperclass() != elementType)
            return false;
        //按位与操作 不为0  则表示包含
        return (elements & (1L << ((Enum<?>)e).ordinal())) != 0;
    }

6、小结

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WofYm9yn-1582708359119)(images/26.png)]

发布了198 篇原创文章 · 获赞 20 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/ZHOUJIAN_TANK/article/details/104520697
今日推荐