Java容器之EnumSet源码分析

一、概述

EnumSet是一个抽象类,不能直接使用,该类有两个子类,RegularEnumSetJumboEnumSet。即枚举值的个数小于等于64时使用RegularEnumSet,大于64时使用JumboEnumSet

这两个子类都是非public的,只能包内访问。

EnumSet需要进行一个操作时首先调用noneOf这个方法,获得一个RegularEnumSet或者JumboEnumSet对象,随后在执行一些操作。

二、源码分析

2.1 属性

/**
 * 枚举的类型
 */
final Class<E> elementType;

/**
 * 枚举类E的所有枚举值
 */
final Enum<?>[] universe;

EnumSet定义了多个静态的工具类方法,其中核心方法如add的实现都留给了子类,下面逐一说明想法方法的实现。

2.2 创建EnumSet

noneOfallOfofrange这些方法都是用来创建EnumSet的。

2.2.1 noneOf方法

noneOf返回一个空的EnumSet

//返回一个空的EnumSet
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 SharedSecrets.getJavaLangAccess()
                    .getEnumConstantsShared(elementType);
}

2.2.2 allOf方法

allOf返回一个包含指定枚举类所有枚举值的EnumSet

//返回一个包含了所有枚举值的EnumSet
public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) {
    EnumSet<E> result = noneOf(elementType);
    //子类实现
    result.addAll();
    return result;
}

2.2.3 of方法

of方法返回一个包含一个或者多个的指定枚举值的EnumSet

//创建只包含一个指定枚举值的EnumSet,有多个重载版本,枚举值从1个到5个
public static <E extends Enum<E>> EnumSet<E> of(E e) {
    EnumSet<E> result = noneOf(e.getDeclaringClass());
    //子类实现
    result.add(e);
    return result;
}
 
@SafeVarargs
public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest) {
    EnumSet<E> result = noneOf(first.getDeclaringClass());
    result.add(first);
    //rest是不定数量的数组,将其中的元素都添加到Set中
    for (E e : rest)
        result.add(e);
    return result;
}

2.2.4 range方法

range返回一个包含指定范围的枚举值的EnumSet

//创建包含指定范围内的枚举值的EnumSet
public static <E extends Enum<E>> EnumSet<E> range(E from, E to) {
    if (from.compareTo(to) > 0)
        throw new IllegalArgumentException(from + " > " + to);
    EnumSet<E> result = noneOf(from.getDeclaringClass());
    //子类实现
    result.addRange(from, to);
    return result;
}

2.3 复制指定的EnumSet

2.3.1 copyOf方法

copyOf用于复制指定的EnumSet

public static <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s) {
    return s.clone();
}
 
public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c) {
    if (c instanceof EnumSet) {
        //如果是EnumSet
        return ((EnumSet<E>)c).clone();
    } else {
        if (c.isEmpty())
            throw new IllegalArgumentException("Collection is empty");
        //如果不是EnumSet,则遍历其中的元素,逐一添加到EnumSet中
        Iterator<E> i = c.iterator();
        E first = i.next();
        EnumSet<E> result = EnumSet.of(first);
        while (i.hasNext())
            result.add(i.next());
        return result;
    }
}

public EnumSet<E> clone() {
    try {
        //调用Object的clone方法
        return (EnumSet<E>) super.clone();
    } catch(CloneNotSupportedException e) {
        throw new AssertionError(e);
    }
}

2.3.2 complementOf方法

complementOf返回原EnumSet中不包含的枚举值。

//返回的EnumSet中包含了所有的枚举值
public static <E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s) {
    EnumSet<E> result = copyOf(s);
    //complement会补齐所有s中不包含的枚举值,由子类实现
    result.complement();
    return result;
}

三、案例

3.1 例1

enum Name{
    SHL,
    ABC,
    DEF,
    AVC,
    DNG
}
 
@Test
public void test() throws Exception {

    //返回一个空的EnumSet
    EnumSet<Name> names = EnumSet.noneOf(Name.class);
    System.out.println(names);
	
    //返回一个包含了所有枚举值的EnumSet
    names = EnumSet.allOf(Name.class);
    System.out.println(names);
	
    //返回一个包含了指定枚举值的EnumSet
    names = EnumSet.of(Name.ABC, Name.DEF);
    System.out.println(names);
	
    //返回一个包含了指定范围的枚举值的EnumSet,起始值都包含
    names = EnumSet.range(Name.ABC, Name.AVC);
    System.out.println(names);
}

输出如下:

[]
[SHL, ABC, DEF, AVC, DNG]
[ABC, DEF]
[ABC, DEF, AVC]

3.2 例2

@Test
public void test2() throws Exception {

    EnumSet<Name> names = EnumSet.allOf(Name.class);
    System.out.println(names);
	
    EnumSet<Name> names2=EnumSet.copyOf(names);
    System.out.println(names2);
    
    names.remove(Name.SHL);
    names2.remove(Name.DNG);
    System.out.println(names);
    System.out.println(names2);
    
    EnumSet<Name> names3 = EnumSet.complementOf(names);
    System.out.println(names3);
}

其输出如下:

[SHL, ABC, DEF, AVC, DNG]
[SHL, ABC, DEF, AVC, DNG]
[ABC, DEF, AVC, DNG]
[SHL, ABC, DEF, AVC]
[SHL]
posted @ 2022-06-03 23:23  夏尔_717  阅读(55)  评论(0编辑  收藏  举报