文章作者:Tyan 博客:noahsnail.com
EnumSet
是Java Set
接口的一个特别实现,在JDK 1.5中开始支持,Enum类型也正式引入到了Java中。与其它保存枚举常量的Set
相比,EnumSet
具有更好的性能,同时其也是Java中的优秀特性之一。下面从三个方面来介绍EnumSet
,what,how,when。
EnumSet
是Set
接口的一个实现,它只能用来存储Enum
常量或其子类,不能存储其它类型。EnumSet
是设计模式中工厂方法创建实例的一个很好例子。
EnumSet
被声明为abstract class
类型,EnumSet
有两种实现方式,RegularEnumSet
和JumboEnumSet
,但是这两种实现方式是包私有的,不能在包外访问,因此必须使用工厂方法来创建并返回EnumSet
实例,不能通过构造函数来创建。EnumSet
中提供了多种创建EnumSet
实例的静态工厂方法,例如of
方法(进行了函数重载),copyOf
方法,noneOf
方法等。
上面已经说了,EnumSet
是一个抽象类,有两个具体实现:java.util.RegularEnumSet
和java.util.JumboEnumSet
。二者的主要区别在于前者使用long
来表示元素的数量,而后者使用long[]
来表示元素的数量。这二者中表示元素数量使用的是位域结构,即通过long
的二进制位数来表示元素数量,例如:RegularEnumSet
使用的是long
表示元素数量,long
数值是通过64位二进制表示的,因此其只能包含的元素最大数量为64,如果元素数目大于64,采用的是JumboEnumSet
表示,JumboEnumSet
的long[]
中有一个long
数值,就能表示64个元素,两个long
数值就能表示128个元素,以此类推。
《Effective Java》中的Item 32讲述了一个EnumSet
的使用场景,推荐去看一下。当你需要对枚举类型进行特定的分组时,你可以使用EnumSet
。例如,一周中有七天,你想将周末单独分出来的时候(enum int pattern):
private enum DayOfWeek{
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
}
private EnumSet weekend = EnumSet.of(SATURDAY,SUNDAY);
EnumSet
中只能包含一种枚举类型。EnumSet
中不能放入null
元素,放入会抛出空指针异常。EnumSet
是线程非安全的。EnumSet
的Iterator是自动防故障和弱一致的,不会抛出并发修改异常,即在迭代过程的中的修改结果不一定会在迭代过程中显示。 EnumSet
是高性能的Java集合。由于是基于数组的访问,因此add
,contains
,next
方法的时间复杂度为O(1)。EnumSet
而不要用HashSet
。EnumSet:
public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E> implements Cloneable, java.io.Serializable {
...
EnumSet(Class<E>elementType, Enum<?>[] universe) {
this.elementType = elementType;
this.universe = universe;
}
/**
* Creates an empty enum set with the specified element type.
*
* @param <E> The class of the elements in the set
* @param elementType the class object of the element type for this enum
* set
* @return An empty enum set of the specified type.
* @throws NullPointerException if <tt>elementType</tt> is null
*/
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);
}
...
}
RegularEnumSet:
class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> {
...
/**
* Bit vector representation of this set. The 2^k bit indicates the
* presence of universe[k] in this set.
*/
private long elements = 0L;
RegularEnumSet(Class<E>elementType, Enum<?>[] universe) {
super(elementType, universe);
}
...
}
JumboEnumSet:
class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> {
private static final long serialVersionUID = 334349849919042784L;
/**
* Bit vector representation of this set. The ith bit of the jth
* element of this array represents the presence of universe[64*j +i]
* in this set.
*/
private long elements[];
// Redundant - maintained for performance
private int size = 0;
JumboEnumSet(Class<E>elementType, Enum<?>[] universe) {
super(elementType, universe);
elements = new long[(universe.length + 63) >>> 6];
}
...
}
import java.util.EnumSet;
import java.util.Set;
public class EnumSetDemo {
private enum Color {
RED(255, 0, 0), GREEN(0, 255, 0), BLUE(0, 0, 255);
private int r;
private int g;
private int b;
private Color(int r, int g, int b) {
this.r = r;
this.g = g;
this.b = b;
}
public int getR() {
return r;
}
public int getG() {
return g;
}
public int getB() {
return b;
}
}
public static void main(String args[]) {
// this will draw line in yellow color
EnumSet<Color> yellow = EnumSet.of(Color.RED, Color.GREEN);
drawLine(yellow);
// RED + GREEN + BLUE = WHITE
EnumSet<Color> white = EnumSet.of(Color.RED, Color.GREEN, Color.BLUE);
drawLine(white);
// RED + BLUE = PINK
EnumSet<Color> pink = EnumSet.of(Color.RED, Color.BLUE);
drawLine(pink);
}
public static void drawLine(Set<Color> colors) {
System.out.println("Requested Colors to draw lines : " + colors);
for (Color c : colors) {
System.out.println("drawing line in color : " + c);
}
}
}
Output:
Requested Colors to draw lines : [RED, GREEN]
drawing line in color : RED
drawing line in color : GREEN
Requested Colors to draw lines : [RED, GREEN, BLUE]
drawing line in color : RED
drawing line in color : GREEN
drawing line in color : BLUE
Requested Colors to draw lines : [RED, BLUE]
drawing line in color : RED
drawing line in color : BLUE
参考资料:
1、https://jaxenter.com/enumset-in-java-regularenumset-vs-jumboenumset-106051.html
2、Effective Java 2.0版本中的Item 1,本文就是在看《Effective Java》时看到的EnumSet
,才想要仔细研究一下EnumSet
的。Item 32讲述了EnumSet
的使用场景。
3、http://brokendreams.iteye.com/blog/2267485
4、http://javarevisited.blogspot.kr/2014/03/how-to-use-enumset-in-java-with-example.html