Jdk1.6 Collections Framework源码解析(11)-EnumSet
作者:大飞
- EnumSet是一种针对Enum类型提供的特殊的Set,每个EnumSet只能基于一个Enum类型来建立。
- EnumSet内部采用位域的方式建立(相当于bit数组),所以操作起来非常高效(几乎所有的基本操作都能在常数时间内完成),包括retainAll和retainAll这种批量操作也一样。
- EnumSet的迭代器中元素顺序按照Enum的自然序(即定义顺序)排列;迭代器是弱一致的,不会抛出ConcurrentModificationException。
- EnumSet的元素不允许为null;EnumSet非线程安全。
- 先看下EnumSet内部结构:
public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E> implements Cloneable, java.io.Serializable { /** * The class of all the elements of this set. */ final Class<E> elementType; /** * All of the values comprising T. (Cached for performance.) */ final Enum[] universe; EnumSet(Class<E>elementType, Enum[] universe) { this.elementType = elementType; this.universe = universe; }
同时会发现,EnumSet的构造方法只是包内可见,外部没法直接构造。实际用起来也是通过of、allOf这样的方法来构造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"); if (universe.length <= 64) return new RegularEnumSet<E>(elementType, universe); else return new JumboEnumSet<E>(elementType, universe); } private static <E extends Enum<E>> E[] getUniverse(Class<E> elementType) { return SharedSecrets.getJavaLangAccess() .getEnumConstantsShared(elementType); }
- 带着上面的2个疑问,我们来进行关键源码的分析:
先来解答第一个问题,接着上面getUniverse中的实现,我们先看下SharedSecrets的源码(可通过openjdk查看):
public class SharedSecrets { ... public static void setJavaLangAccess(JavaLangAccess jla) { javaLangAccess = jla; } public static JavaLangAccess getJavaLangAccess() { return javaLangAccess; }
原来在JVM初始化过程中会有初始化系统类的过程,这个过程的详细代码可参见hotspot/src/share/vm/runtime/thread.cpp中的call_initializeSystemClass方法,代码就不贴了。这个方法其实是调用了System类的initializeSystemClass方法:
/** * Initialize the system class. Called after thread initialization. */ private static void initializeSystemClass() { ... // Workaround until DownloadManager initialization is revisited. // Make JavaLangAccess available early enough for internal // Shutdown hooks to be registered setJavaLangAccess(); ... }
再看下这个setJavaLangAccess方法:
private static void setJavaLangAccess() { // Allow privileged classes outside of java.lang sun.misc.SharedSecrets.setJavaLangAccess(new sun.misc.JavaLangAccess(){ public sun.reflect.ConstantPool getConstantPool(Class klass) { return klass.getConstantPool(); } public void setAnnotationType(Class klass, AnnotationType type) { klass.setAnnotationType(type); } public AnnotationType getAnnotationType(Class klass) { return klass.getAnnotationType(); } public <E extends Enum<E>> E[] getEnumConstantsShared(Class<E> klass) { return klass.getEnumConstantsShared(); } public void blockedOn(Thread t, Interruptible b) { t.blockedOn(b); } public void registerShutdownHook(int slot, Runnable r) { Shutdown.add(slot, r); } public int getStackTraceDepth(Throwable t) { return t.getStackTraceDepth(); } public StackTraceElement getStackTraceElement(Throwable t, int i) { return t.getStackTraceElement(i); } }); }
可见,其中的实现是直接调用了传入Class的getEnumConstantsShared方法,继续看:
T[] getEnumConstantsShared() { if (enumConstants == null) { if (!isEnum()) return null; try { final Method values = getMethod("values"); java.security.AccessController.doPrivileged (new java.security.PrivilegedAction() { public Object run() { values.setAccessible(true); return null; } }); enumConstants = (T[])values.invoke(null); } // These can happen when users concoct enum-like classes // that don't comply with the enum spec. catch (InvocationTargetException ex) { return null; } catch (NoSuchMethodException ex) { return null; } catch (IllegalAccessException ex) { return null; } } return enumConstants; }
好吧,我们来写一个简单的枚举:
public enum Laugh { HAHA, HEHE, HEIHEI }
然后用javap分析下这个class(javap -p -c 目标class路径):
public final class com.brokendreams.Laugh extends java.lang.Enum<com.brokendreams.Laugh> { public static final com.brokendreams.Laugh HAHA; public static final com.brokendreams.Laugh HEHE; public static final com.brokendreams.Laugh HEIHEI; private static final com.brokendreams.Laugh[] ENUM$VALUES; static {}; Code: 0: new #1 // class com/brokendreams/Laugh 3: dup 4: ldc #14 // String HAHA 6: iconst_0 7: invokespecial #15 // Method "<init>":(Ljava/lang/String;I)V 10: putstatic #19 // Field HAHA:Lcom/brokendreams/Laugh; 13: new #1 // class com/brokendreams/Laugh 16: dup 17: ldc #21 // String HEHE 19: iconst_1 20: invokespecial #15 // Method "<init>":(Ljava/lang/String;I)V 23: putstatic #22 // Field HEHE:Lcom/brokendreams/Laugh; 26: new #1 // class com/brokendreams/Laugh 29: dup 30: ldc #24 // String HEIHEI 32: iconst_2 33: invokespecial #15 // Method "<init>":(Ljava/lang/String;I)V 36: putstatic #25 // Field HEIHEI:Lcom/brokendreams/Laugh; 39: iconst_3 40: anewarray #1 // class com/brokendreams/Laugh 43: dup 44: iconst_0 45: getstatic #19 // Field HAHA:Lcom/brokendreams/Laugh; 48: aastore 49: dup 50: iconst_1 51: getstatic #22 // Field HEHE:Lcom/brokendreams/Laugh; 54: aastore 55: dup 56: iconst_2 57: getstatic #25 // Field HEIHEI:Lcom/brokendreams/Laugh; 60: aastore 61: putstatic #27 // Field ENUM$VALUES:[Lcom/brokendreams/Laugh; 64: return private com.brokendreams.Laugh(java.lang.String, int); Code: 0: aload_0 1: aload_1 2: iload_2 3: invokespecial #31 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V 6: return public static com.brokendreams.Laugh[] values(); Code: 0: getstatic #27 // Field ENUM$VALUES:[Lcom/brokendreams/Laugh; 3: dup 4: astore_0 5: iconst_0 6: aload_0 7: arraylength 8: dup 9: istore_1 10: anewarray #1 // class com/brokendreams/Laugh 13: dup 14: astore_2 15: iconst_0 16: iload_1 17: invokestatic #35 // Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V 20: aload_2 21: areturn public static com.brokendreams.Laugh valueOf(java.lang.String); Code: 0: ldc #1 // class com/brokendreams/Laugh 2: aload_0 3: invokestatic #43 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum; 6: checkcast #1 // class com/brokendreams/Laugh 9: areturn }
首先看下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); }
下面利用我们上面定义的枚举,写个例子:
public static void main(String[] args) { try { EnumSet<Laugh> laughs = EnumSet.noneOf(Laugh.class); /* * 0...0 0 0 0 0 0 0 0 0 * 56个 */ Field elementsField = laughs.getClass().getDeclaredField("elements"); elementsField.setAccessible(true); laughs.add(Laugh.HEHE); /* * 0...0 0 0 0 0 0 0 1 0 * 56个 HEHE */ long elements = elementsField.getLong(laughs); System.out.println(Long.toBinaryString(elements)); laughs.add(Laugh.HAHA); /* * 0...0 0 0 0 0 0 0 1 1 * 56个 HEHE HAHA */ elements = elementsField.getLong(laughs); System.out.println(Long.toBinaryString(elements)); laughs.add(Laugh.HEIHEI); /* * 0...0 0 0 0 0 0 1 1 1 * 56个 HEIHEI HEHE HAHA */ elements = elementsField.getLong(laughs); System.out.println(Long.toBinaryString(elements)); } catch (Exception e) { e.printStackTrace(); } }
输出如下:
10 11 111
顺便看下add方法的实现:
public boolean add(E e) { typeCheck(e); long oldElements = elements; elements |= (1L << ((Enum)e).ordinal()); return elements != oldElements; }
再看一个EnumSet的方法-allOf的实现:
public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) { EnumSet<E> result = noneOf(elementType); result.addAll(); return result; }
首先调用了noneOf,得到一个空的EnumSet集合,然后调用addAll方法添加所有元素,看看RegularEnumSet中addAll的实现细节:
void addAll() { if (universe.length != 0) elements = -1L >>> -universe.length; }
再看下JumboEnumSet:
class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> { /** * 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]; }
剩下的代码不看了,都是位操作,就不在这里啰嗦了,EnumSet的源码解析就到这里!有不对的地方请指正!
相关推荐
《Jdk1.6 Collections Framework源码解析(2)-LinkedList》 LinkedList是Java集合框架中的一个重要的类,它是List接口的实现,同时继承了AbstractSequentialList,并实现了Deque接口。LinkedList是一种双链表结构,...
1.okhttp3.8源码使用jdk1.6重新编译,已集成了okio,在javaweb项目中使用,未在安卓项目中使用 2.okhttp3.8源码使用jdk1.6重新编译_okhttp3.8.0-jdk1.6.jar
aspose-words-15.8.0-jdk1.6aspose-words-15.8.0-jdk1.6aspose-words-15.8.0-jdk1.6aspose-words-15.8.0-jdk1.6aspose-words-15.8.0-jdk1.6aspose-words-15.8.0-jdk1.6aspose-words-15.8.0-jdk1.6aspose-words-...
1. 解压缩"java-jdk1.6-jdk-6u45-windows-x64.zip"文件,这将释放出"jdk-6u45-windows-x64.exe"可执行文件。 2. 双击运行"jdk-6u45-windows-x64.exe",安装向导会引导你完成安装过程。通常,你需要选择安装路径,...
java环境搭建 jdk6(包含jre)64位 jdk-6u45-windows-x64
2部分: jdk-1.6-windows-64-01 jdk-1.6-windows-64-02
下载的压缩包文件"jdk-6u45-windows-x64(1.6 64).exe"是Windows 64位系统的安装程序。安装过程中,用户需要选择安装路径,并设置环境变量,包括`JAVA_HOME`指向JDK的安装目录,`PATH`添加JDK的bin目录,确保系统可以...
logback-cfca-jdk1.6-3.1.0.0.jar
三部分: jdk-1.6-linux-64-1 jdk-1.6-linux-64-2 jdk-1.6-linux-64-3
标题中的“jdk1.6集成jjwt的问题”指的是在Java Development Kit (JDK) 版本1.6的环境下,尝试整合JSON Web Token (JWT) 库jjwt时遇到的挑战。JWT是一种开放标准(RFC 7519),用于在各方之间安全地传输信息作为 ...
压缩包中的文件`jdk-6u45-windows-i586.exe`是JDK 1.6更新45的Windows 32位安装程序。安装步骤通常包括: 1. 下载并运行安装程序。 2. 遵循安装向导的提示,选择安装路径和组件。 3. 设置环境变量,包括`JAVA_HOME`...
这个压缩包文件"jdk-6u45-linux-x64.zip"包含的是JDK 1.6.0_45(也被称为6u45或1.6u45)的64位Linux版本。JDK 1.6是Java平台标准版的一个重要版本,它提供了许多功能和性能改进,是许多企业级应用的基础。 JDK 1.6u...
- 这可能是ZXing库的完整源码包,专门针对JDK1.6编译,包含了所有必要的源文件和资源,供开发者进行更深度的定制和集成。 总之,ZXing库是一个强大的条形码和二维码工具,这个特别适配JDK1.6的版本为那些仍在使用...
Linux64位环境下的jdk6安装包:jdk-6u45-linux-x64.bin。 由于积分无法修改,现提供网盘下载地址: https://pan.baidu.com/s/1BE55ImTxZTQO6T22051P2g 提取码:5wvm
三部分: jdk-1.6-linux-64-1 jdk-1.6-linux-64-2 jdk-1.6-linux-64-3
软件介绍: jdk-6u45-linux-x64.bin为LINUX系统下的jdk1.6软件安装包,6u45版应该是JDK1.6的最高版本了,在搭建项目测试时需要安装的运行环境,官网现在不一定能够找得到。
三部分: jdk-1.6-windows-32-1 jdk-1.6-windows-32-2 jdk-1.6-windows-32-3
三部分: jdk-1.6-linux-64-1 jdk-1.6-linux-64-2 jdk-1.6-linux-64-3
mac for jdk1.6 jdk6 安装版 里面有两个jdk1.6的安装包,都可以用 如果电脑上安装有1.7,1.8等高版本jdk就不要再下安装包了,安装包安装会报错 命令是这个:brew install java6或 brew install homebrew/cask-...
"jdk-6u45-windows-x64"指的是这个版本的第45个更新,专门针对Windows操作系统64位架构设计。 在Java 6中,有几个显著的改进和新特性: 1. **动态语言支持**:JDK1.6引入了Java Dynamic Language Toolkit (JDT),...