java中枚举声明需用到enum关键字简单的如:
public enum TestEnum { Mon, Tue, Wen, Fri }
但是我们查看一下编译后得到的汇编就能知道,enum编译后得到的还是一个class,现在用javap -verbose TestEnum命令查看编译得到的class文件:
Classfile /F:/TestEnum.class Last modified 2017-5-8; size 868 bytes MD5 checksum 485a9071bf44ca9406beceea0dbca950 Compiled from "TestEnum.java" public final class TestEnum extends java.lang.Enum<TestEnum> minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM Constant pool: #1 = Fieldref #4.#38 // TestEnum.$VALUES:[LTestEnum; #2 = Methodref #39.#40 // "[LTestEnum;".clone:()Ljava/lang/Object; #3 = Class #23 // "[LTestEnum;" #4 = Class #41 // TestEnum #5 = Methodref #16.#42 // java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum; #6 = Methodref #16.#43 // java/lang/Enum."<init>":(Ljava/lang/String;I)V #7 = String #17 // Mon #8 = Methodref #4.#43 // TestEnum."<init>":(Ljava/lang/String;I)V #9 = Fieldref #4.#44 // TestEnum.Mon:LTestEnum; #10 = String #19 // Tue #11 = Fieldref #4.#45 // TestEnum.Tue:LTestEnum; #12 = String #20 // Wen #13 = Fieldref #4.#46 // TestEnum.Wen:LTestEnum; #14 = String #21 // Fri #15 = Fieldref #4.#47 // TestEnum.Fri:LTestEnum; #16 = Class #48 // java/lang/Enum #17 = Utf8 Mon #18 = Utf8 LTestEnum; #19 = Utf8 Tue #20 = Utf8 Wen #21 = Utf8 Fri #22 = Utf8 $VALUES #23 = Utf8 [LTestEnum; #24 = Utf8 values #25 = Utf8 ()[LTestEnum; #26 = Utf8 Code #27 = Utf8 LineNumberTable #28 = Utf8 valueOf #29 = Utf8 (Ljava/lang/String;)LTestEnum; #30 = Utf8 <init> #31 = Utf8 (Ljava/lang/String;I)V #32 = Utf8 Signature #33 = Utf8 ()V #34 = Utf8 <clinit> #35 = Utf8 Ljava/lang/Enum<LTestEnum;>; #36 = Utf8 SourceFile #37 = Utf8 TestEnum.java #38 = NameAndType #22:#23 // $VALUES:[LTestEnum; #39 = Class #23 // "[LTestEnum;" #40 = NameAndType #49:#50 // clone:()Ljava/lang/Object; #41 = Utf8 TestEnum #42 = NameAndType #28:#51 // valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum; #43 = NameAndType #30:#31 // "<init>":(Ljava/lang/String;I)V #44 = NameAndType #17:#18 // Mon:LTestEnum; #45 = NameAndType #19:#18 // Tue:LTestEnum; #46 = NameAndType #20:#18 // Wen:LTestEnum; #47 = NameAndType #21:#18 // Fri:LTestEnum; #48 = Utf8 java/lang/Enum #49 = Utf8 clone #50 = Utf8 ()Ljava/lang/Object; #51 = Utf8 (Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum; { public static final TestEnum Mon; descriptor: LTestEnum; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM public static final TestEnum Tue; descriptor: LTestEnum; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM public static final TestEnum Wen; descriptor: LTestEnum; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM public static final TestEnum Fri; descriptor: LTestEnum; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM private static final TestEnum[] $VALUES; descriptor: [LTestEnum; flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC public static TestEnum[] values(); descriptor: ()[LTestEnum; flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=0, args_size=0 0: getstatic #1 // Field $VALUES:[LTestEnum; 3: invokevirtual #2 // Method "[LTestEnum;".clone:()Ljava/lang/Object; 6: checkcast #3 // class "[LTestEnum;" 9: areturn LineNumberTable: line 1: 0 public static TestEnum valueOf(java.lang.String); descriptor: (Ljava/lang/String;)LTestEnum; flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: ldc #4 // class TestEnum 2: aload_0 3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum; 6: checkcast #4 // class TestEnum 9: areturn LineNumberTable: line 1: 0 private TestEnum(); descriptor: (Ljava/lang/String;I)V flags: ACC_PRIVATE Code: stack=3, locals=3, args_size=3 0: aload_0 1: aload_1 2: iload_2 3: invokespecial #6 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V 6: return LineNumberTable: line 1: 0 Signature: #33 // ()V static {}; descriptor: ()V flags: ACC_STATIC Code: stack=4, locals=0, args_size=0 0: new #4 // class TestEnum 3: dup 4: ldc #7 // String Mon 6: iconst_0 7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V 10: putstatic #9 // Field Mon:LTestEnum; 13: new #4 // class TestEnum 16: dup 17: ldc #10 // String Tue 19: iconst_1 20: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V 23: putstatic #11 // Field Tue:LTestEnum; 26: new #4 // class TestEnum 29: dup 30: ldc #12 // String Wen 32: iconst_2 33: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V 36: putstatic #13 // Field Wen:LTestEnum; 39: new #4 // class TestEnum 42: dup 43: ldc #14 // String Fri 45: iconst_3 46: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V 49: putstatic #15 // Field Fri:LTestEnum; 52: iconst_4 53: anewarray #4 // class TestEnum 56: dup 57: iconst_0 58: getstatic #9 // Field Mon:LTestEnum; 61: aastore 62: dup 63: iconst_1 64: getstatic #11 // Field Tue:LTestEnum; 67: aastore 68: dup 69: iconst_2 70: getstatic #13 // Field Wen:LTestEnum; 73: aastore 74: dup 75: iconst_3 76: getstatic #15 // Field Fri:LTestEnum; 79: aastore 80: putstatic #1 // Field $VALUES:[LTestEnum; 83: return LineNumberTable: line 2: 0 line 3: 13 line 4: 26 line 5: 39 line 1: 52 } Signature: #35 // Ljava/lang/Enum<LTestEnum;>; SourceFile: "TestEnum.java"
现在一点一点解释
1.enum最终编译得到一个继承java.lang.Enum的final class(Enum的源码这里不做讲解,很简单)
2.这个类TestEnum类,有几个类型为自身的静态最终变量Mon、Tue、Wen、Fri也就是在enum中的几个声明,以及一个TestEnum[]数组变量$VALUES
3.静态方法values(),作用是返回该类的静态变量数组$VALUES
4.静态方法valueOf(),内部调用Enum类的方法
public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) { //enumConstantDirectory返回一个第一次使用时懒加载的,简单名称与Enum实例 键值对的map T result = enumType.enumConstantDirectory().get(name); if (result != null) return result; if (name == null) throw new NullPointerException("Name is null"); throw new IllegalArgumentException( "No enum constant " + enumType.getCanonicalName() + "." + name); }
5.私有构造方法private TestEnum();内部就是调用enum的protected构造方法
6.静态代码块,它的作用是以枚举各个元素对应的String值和从0开始的int值为参数,依次初始化TestEnum对象并赋值给对应的静态最终变量(int值跟enum的ordinal相对应,String值跟enum的name相对应),接下来就是把这些静态变量值放到$VALUES数组中
所有枚举就是含有自身静态变量实例的类