The underlying implementation of enumerations in the JDK

Source: Internet
Author: User
Tags constant definition

Premise

The previous article reviewed the underlying implementation of the annotations in the JDK, which is as common as annotations, but the underlying implementation is more mysterious than the enumeration type. Taking advantage of the last two days of the National Day holiday, the underlying implementation of the enumeration in the JDK is also explored.

Find the essence by example

When exploring the underlying implementation of JDK annotations, the whole process is a bit "foresight" because of the pre-reference to a lot of data, and here we try to look at the underlying implementation of annotations with an unknown perspective. First define a phone operating system type enumeration Phoneosenum:

package club.throwable.enumeration;public enum PhoneOsEnum {    /**     * 安卓     */    ANDROID(1, "android"),    /**     * ios     */    IOS(2, "ios");    private final Integer type;    private final String typeName;    PhoneOsEnum(Integer type, String typeName) {        this.type = type;        this.typeName = typeName;    }    public Integer getType() {        return type;    }    public String getTypeName() {        return typeName;    }}

This is a very simple enumeration, and then decompile the bytecode using the JDK's anti-compilation tool, executing the following command:

javap -c -v D:\Projects\rxjava-seed\target\classes\club\throwable\enumeration\PhoneOsEnum.class

Then you get a very long byte code about Phoneosenum.class, which is all posted here:

Classfile/d:/projects/rxjava-seed/target/classes/club/throwable/enumeration/phoneosenum.class Last Modified 2018-10-6; Size 1561 bytes MD5 checksum 6d3186042f54233219000927a2f196aa Compiled from ' Phoneosenum.java ' public final class club.th Rowable.enumeration.PhoneOsEnum extends java.lang.enum<club.throwable.enumeration.phoneosenum> minor version         : 0 Major version:52 Flags:acc_public, acc_final, Acc_super, acc_enumconstant pool: #1 = Fieldref #4. #49   Club/throwable/enumeration/phoneosenum. $VALUES: [Lclub/throwable/enumeration/phoneosenum; #2 = MethodRef #50. #51//"[Lclub/throwable/enumeration/phoneosenum;".   Clone: () Ljava/lang/object;   #3 = Class #26//"[Lclub/throwable/enumeration/phoneosenum;"]        #4 = Class #52//Club/throwable/enumeration/phoneosenum #5 = MethodRef #17. #53 Java/lang/enum.valueof: (Ljava/lang/class;   ljava/lang/string;) Ljava/lang/enum; #6 = MethodrEF #17. #54//Java/lang/enum. " <init>:(ljava/lang/string;i) V #7 = Fieldref #4. #55//Club/throwable/enumeration/phoneosenum.ty   Pe:ljava/lang/integer;   #8 = Fieldref #4. #56//club/throwable/enumeration/phoneosenum.typename:ljava/lang/string; #9 = String #18//ANDROID #10 = MethodRef #57. #58//java/lang/integer.valueof: (I  ) Ljava/lang/integer; #11 = String #59//android #12 = MethodRef #4. #60//club/throwable/enumeration/ Phoneosenum. " <init> ":(Ljava/lang/string;iljava/lang/integer; ljava/lang/string;) V #13 = Fieldref #4. #61//Club/throwable/enumeration/phoneosenum.android:lclub/thro  Wable/enumeration/phoneosenum; #14 = string #20//iOS #15 = string #62//iOS #16 = Fieldref # 4. #63//club/throwable/enumeration/phoneosenum.ios:lclub/throwable/enumeration/Phoneosenum; #17 = Class #64//Java/lang/enum #18 = Utf8 ANDROID #19 = Utf8 lclu  B/throwable/enumeration/phoneosenum;  #20 = Utf8 IOS #21 = Utf8 type #22 = Utf8 Ljava/lang/integer;  #23 = Utf8 TypeName #24 = Utf8 ljava/lang/string;  #25 = Utf8 $VALUES #26 = Utf8 [Lclub/throwable/enumeration/phoneosenum;  #27 = Utf8 Values #28 = Utf8 () [Lclub/throwable/enumeration/phoneosenum;               #29 = Utf8 Code #30 = Utf8 linenumbertable #31 = Utf8 valueOf #32 = Utf8  (ljava/lang/string;) Lclub/throwable/enumeration/phoneosenum; #33 = Utf8 localvariabletable #34 = Utf8 name #35 = Utf8 <init> #36 = U Tf8 (Ljava/lang/string;iljava/lang/integer; ljava/lang/string) V #37 = Utf8 this #38 = UtF8 Signature #39 = Utf8 (Ljava/lang/integer;  ljava/lang/string;) V #40 = Utf8 GetType #41 = Utf8 () Ljava/lang/integer;  #42 = Utf8 Gettypename #43 = Utf8 () ljava/lang/string; #44 = Utf8 <clinit> #45 = Utf8 () V #46 = Utf8 ljava/lang/enum<lclub/t  hrowable/enumeration/phoneosenum;>;  #47 = Utf8 sourcefile #48 = Utf8 Phoneosenum.java #49 = nameandtype #25: #26//  $VALUES: [Lclub/throwable/enumeration/phoneosenum;  #50 = Class #26//"[Lclub/throwable/enumeration/phoneosenum;"]  #51 = Nameandtype #65: #66//Clone: () Ljava/lang/object; #52 = Utf8 Club/throwable/enumeration/phoneosenum #53 = nameandtype #31: #67//valueOf: (Ljava /lang/class;  ljava/lang/string;) Ljava/lang/enum; #54 = Nameandtype #35: #68//"<init>":(ljava/lang/stRing;i) V #55 = Nameandtype #21: #22//Type:ljava/lang/integer;  #56 = Nameandtype #23: #24//typename:ljava/lang/string; #57 = Class #69//Java/lang/integer #58 = Nameandtype #31: #70//ValueOf: (I) ljava/  Lang/integer; #59 = Utf8 android #60 = Nameandtype #35: #36//"<init>":(Ljava/lang/string;iljava/lang /integer;  ljava/lang/string;) V #61 = Nameandtype #18: #19//Android:lclub/throwable/enumeration/phoneosenum;  #62 = Utf8 iOS #63 = nameandtype #20: #19//Ios:lclub/throwable/enumeration/phoneosenum;  #64 = Utf8 Java/lang/enum #65 = Utf8 Clone #66 = Utf8 () ljava/lang/object; #67 = Utf8 (ljava/lang/class;  ljava/lang/string;) Ljava/lang/enum; #68 = Utf8 (ljava/lang/string;i) V #69 = Utf8 Java/lang/integer #70 = Utf8 (I) L Java/lang/integer; {PublIC static final Club.throwable.enumeration.PhoneOsEnum ANDROID;    Descriptor:lclub/throwable/enumeration/phoneosenum;    Flags:acc_public, Acc_static, acc_final, Acc_enum public STATIC FINAL club.throwable.enumeration.PhoneOsEnum IOS;    Descriptor:lclub/throwable/enumeration/phoneosenum;    Flags:acc_public, Acc_static, acc_final, Acc_enum public STATIC club.throwable.enumeration.phoneosenum[] values ();    Descriptor: () [Lclub/throwable/enumeration/phoneosenum;  Flags:acc_public, Acc_static code:stack=1, locals=0, args_size=0 0:getstatic #1//         Field $VALUES: [Lclub/throwable/enumeration/phoneosenum; 3:invokevirtual #2//Method "[Lclub/throwable/enumeration/phoneosenum;].         Clone: () Ljava/lang/object;         6:checkcast #3//Class "[Lclub/throwable/enumeration/phoneosenum;"] 9:areturn linenumbertable:line 9:0 public static Club.throwable.enumeration.PhoneOsEnum valueOf (java.lang.String);    Descriptor: (ljava/lang/string;) Lclub/throwable/enumeration/phoneosenum;  Flags:acc_public, Acc_static code:stack=2, Locals=1, args_size=1 0:ldc #4// Class Club/throwable/enumeration/phoneosenum 2:aload_0 3:invokestatic #5//Method ja Va/lang/enum.valueof: (Ljava/lang/class;         ljava/lang/string;) Ljava/lang/enum; 6:checkcast #4//class Club/throwable/enumeration/phoneosenum 9:areturn Linenumbertab Le:line 9:0 localvariabletable:start Length Slot Name Signature 0 0 Nam  e ljava/lang/string;    Public Java.lang.Integer getType ();    Descriptor: () Ljava/lang/integer;                  Flags:acc_public code:stack=1, Locals=1, args_size=1 0:aload_0 1:getfield #7         Field Type:ljava/lang/integer; 4:areturn Linenumbertable:line 31:0 LocalvAriabletable:start Length Slot Name Signature 0 5 0 This lclub/throwable/enumeration/  Phoneosenum;    Public java.lang.String gettypename ();    Descriptor: () ljava/lang/string;                  Flags:acc_public code:stack=1, Locals=1, args_size=1 0:aload_0 1:getfield #8         Field typename:ljava/lang/string;            4:areturn linenumbertable:line 35:0 localvariabletable:start Length Slot Name Signature  0 5 0 This lclub/throwable/enumeration/phoneosenum;    static {};                  Descriptor: () V flags:acc_static code:stack=6, locals=0, args_size=0 0:new #4  Class Club/throwable/enumeration/phoneosenum 3:dup 4:LDC #9//String ANDROID 6:iconst_0 7:iconst_1 8:invokestatic #10//Method Java/lang/integer.      ValueOf: (I) Ljava/lang/integer;  11:LDC #11//String Android 13:invokespecial #12//Method "<init > ":(Ljava/lang/string;iljava/lang/integer; ljava/lang/string;) V 16:putstatic #13//Field Android:lclub/throwable/enumeration/phoneosenum        ;           19:new #4//class Club/throwable/enumeration/phoneosenum 22:dup 23:LDC                 #14//String IOS 25:iconst_1 26:iconst_2 27:invokestatic #10        Method java/lang/integer.valueof: (I) Ljava/lang/integer; 30:LDC #15//String iOS 32:invokespecial #12//Method "<init>": (Ljava/lang/string;iljava/lang/integer;        ljava/lang/string;) V 35:putstatic #16//Field ios:lclub/throwable/enumeration/phoneosenum; 38:iconst_2 39:anewarray #4//Class Club/throwable/enumeration/phoneosenUm 42:dup 43:iconst_0 44:getstatic #13//Field Android:lclub/throwable/enumer        Ation/phoneosenum; 47:aastore 48:dup 49:iconst_1 50:getstatic #16//Field ios:lclub/throwable/e        Numeration/phoneosenum;        53:aastore 54:putstatic #1//Field $VALUES: [Lclub/throwable/enumeration/phoneosenum;                          57:return linenumbertable:line 14:0 Line 19:19 line 9:38}signature: #46 ljava/lang/enum<lclub/throwable/enumeration/phoneosenum;>; SourceFile: "Phoneosenum.java"

Look at the signature of the class first public final class Club.throwable.enumeration.PhoneOsEnum extends java.lang.enum< Club.throwable.enumeration.phoneosenum> , Its parent class is java.lang.Enum, and the generic of the parent class is the self-club.throwable.enumeration.PhoneOsEnum. The readability of the above bytecode is relatively low and is translated directly into Java code (of course, we cannot declare a class directly inheriting java.lang.Enum, just to illustrate the prototype of the anti-compiled enum class) as follows:

Public final class Phoneosenumeration extends enum<phoneosenumeration> {public phoneosenumeration (String name, I        NT ordinal, Integer type, String typeName) {super (name, ordinal);        This.type = type;    This.typename = TypeName;    } public Integer GetType () {return type;    } public String Gettypename () {return typeName;    } public static phoneosenumeration[] values () {return $VALUES. Clone ();    public static phoneosenumeration valueOf (String name) {return enum.valueof (Phoneosenumeration.class, name);    } private final Integer type;    Private final String TypeName;    private static final phoneosenumeration ANDROID;    private static final phoneosenumeration IOS;    private static final phoneosenumeration[] $VALUES;        static {android = new Phoneosenumeration ("Android", 0, 1, "Android");        iOS = new Phoneosenumeration ("ios", 1, 2, "ios"); $VALUES = new Phoneosenumeration[]{android, IOS}; }}

As a general rule, member variables are declared through static code blocks, where it is important to note that when a parent enum is instantiated, it needs to overwrite the parent class constructor protected Enum(String name, int ordinal) , and the implementation of the other methods is simple.

Enumeration description of JDK

International practice, first look at the definition and description of enumeration types in the JavaSE-8 language specification: JLS-8.9

Feel a bit familiar, summarize the important content has the following points:

    • The declaration format of an enumeration is: {ClassModifier} enum Identifier [Superinterfaces] EnumBody ClassModifier is a modifier, identifier is the name of an enumeration that can be likened to a class name, and an enumeration type can implement an interface.
    • Enum types cannot use an abstract or final decoration, or a compilation error will occur.
    • The direct superclass of an enumeration type is java.lang.Enum.
    • An enumeration type has no other instance than the enumeration constant definition, that is, the enumeration type cannot be instantiated.
    • Enumeration type disables the instantiation of the reflection operation (this is the reason why the enumeration is recommended in Java for effetive).

The source code for the common parent of the enumeration Java.lang.Enum is as follows (all comments have been removed):

Public abstract class Enum<e extends enum<e>> implements Comparable<e>, Serializable {private     Final String name;    Public final String name () {return name;    } private final int ordinal;    Public final int ordinal () {return ordinal;        } protected Enum (String name, int ordinal) {this.name = name;    This.ordinal = ordinal;    } public String toString () {return name;    } Public Final Boolean equals (Object other) {return this==other;    } public final int hashcode () {return super.hashcode ();    } Protected final Object clone () throws Clonenotsupportedexception {throw new clonenotsupportedexception ();        Public final int compareTo (E o) {enum<?> other = (enum<?>) o;        Enum<e> self = this; if (self.getclass () = Other.getclass () &&//Optimization Self.getdeclaringclass ()! = Other.getdeclari Ngclass ()) throW new ClassCastException ();    return self.ordinal-other.ordinal;        } Public final class<e> Getdeclaringclass () {class<?> clazz = GetClass ();        class<?> zuper = Clazz.getsuperclass (); return (Zuper = = Enum.class)?    (class<e>) Clazz: (class<e>) Zuper;                                                } public static <t extends enum<t>> T valueOf (class<t> enumtype,        String name) {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); } Protected final void Finalize () {} private void ReadObject (ObjectInputStream in) throws IOException, Cla    ssnotfoundexception {throw new Invalidobjectexception ("Can ' t deserialize enum");  }  private void Readobjectnodata () throws objectstreamexception {throw new Invalidobjectexception ("Can ' t Deserializ    e enum ");             }                              }

Most of the methods are relatively simple, noteworthy points are:

    • 1, the valueOf method relies on Class<?>#enumConstantDirectory() , after the first call of this method is completed, the result is cached in the Class<?>#enumConstantDirectory variable.
    • 2, enum implements the Serializable interface, but readObject and readObjectNoData directly throws the invalidobjectexception exception, note that is "prevent the default deserialization", which is somewhat unclear, Since disabling deserialization is the reason for implementing the Serializable interface, it is possible to consider whether implementing the serializable interface should be given to the developer.
    • 3. Enum disables cloning.
Summary

The underlying implementation of the enumeration in the JDK is that the enumeration class that is declared with the enum keyword is compiled and eventually becomes public The final adornment implements the generic interface Java.lang.Enum and specifies that the generic parameter is the normal Java class for itself, and the member property and the method implementation are all formed after compilation, and the member variables of the enumeration type are declared by a static block of code.

(The end of this article c-1-d e-20181006)

The underlying implementation of enumerations in the JDK

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.