首页 > 代码库 > Java enum枚举是怎么回事

Java enum枚举是怎么回事

Java1.5之前是没有枚举的,如果想使用类似枚举的特性,也即是需要使用常量的时候,可以通过如下代码完成:

Java中的常量定义:

publicclassSex2 {

    publicstaticfinalintGIRL = 1;

    publicstaticfinalintBOY = 2;

    publicstaticvoid main(String[]args) {

        System.out.println(Sex2.GIRL);

    }

}

但是这样做有个缺点,就是不够直观,我们打印出Sex2.GIRL看到的却是数字1。于是我们有了下面的改进:

改进一:

publicclassSex3 {

    publicstaticfinal StringGIRL ="GIRL";

    publicstaticfinal StringBOY ="BOY";

    publicstaticvoid main(String[]args) {

        System.out.println(Sex3.GIRL);

    }

}

现在就比较直观了,我们打印出Sex3.GIRL,就能看到是GIRL,意思十分明确。可是问题又来了,如果我有一个方法接受GIRL或BOY为参数,但是我不能保证别人调用方法时使用别的字符串,比如“KID”。于是我们又有了进一步的改进:

改进二:

publicclassSex4 {

    publicstaticfinal Sex4GIRL =new Sex4("GIRL");

    publicstaticfinal Sex4BOY =new Sex4("GIRL");

    private Stringsex;

    private Sex4(Stringsex){

        this.sex =sex;

    }

    public String toString(){

        returnsex;

    }

}

这样在需要使用性别的地方,就可以通过使用Sex4这个类型来保证性别时能是BOY或者GIRL了。比如类似如下函数的定义:

publicvoidoutSex(Sex4sex){

    System.out.println(sex);

}

但是现在问题又来了,我们只是要使用两个常量,但是却要写那么多行代码(定义Sex4的时候),有没有简单的做法呢?答案当然是有,为了简化我们的代码书写,Java enum类型横空出世,下面的代码跟上面Sex4的定义是等效的:

改进三,enum类型横空出世:

publicenumSexEnum {

    GIRL,

    BOY

}

我的天!简直不敢相信,真是太简洁了!那需要使用他的地方该如何定义呢:

publicvoidoutSex(SexEnumsex){

    System.out.println(sex);

}

疑问:既然Java1.5之前没有enum,那么1.5多出来的enum到底是什么东西?他跟一个普通的类有什么不同呢?

告诉你吧,实际上Java 中的enum就是就是类,定义了一个enum就是定义了一个类,对SexEnum.class的反编译印证了这一点。

javap -p SexEnum.class


Compiled from "SexEnum.java"

public final class SexEnum extendsjava.lang.Enum<SexEnum> {

 public static final SexEnum GIRL;

 public static final SexEnum BOY;

 private static final SexEnum[] $VALUES;

 public static SexEnum[] values();

 public static SexEnum valueOf(java.lang.String);

 private SexEnum();

 static {};

}

我们看到SexEnum是一个被final修饰的类,继承自java.lang.Enum。还看到除了我们自己定义的GIRL和BOY成员之外,类里面还多了四个成员和一个静态代码块。请注意构造方法是私有的!你可能已经猜到了,这里的继承关系,及这些成员是编译器帮我们加上的。通过反编译可以看到这些成员函数以及静态代码块对应的JVM字节码:

javap -c SexEnum.class


Compiled from "SexEnum.java"

public final class SexEnum extendsjava.lang.Enum<SexEnum> {

 public static final SexEnum GIRL;

 

 public static final SexEnum BOY;

 

 public static SexEnum[] values();

   Code:

      0: getstatic     #1                  // Field $VALUES:[LSexEnum;

      3: invokevirtual #2                 // Method "[LSexEnum;".clone:()Ljava/lang/Object;

      6: checkcast     #3                  // class"[LSexEnum;"

       9: areturn

 

 public static SexEnum valueOf(java.lang.String);

   Code:

      0: ldc           #4                  // class SexEnum

      2: aload_0

      3: invokestatic  #5                  // Methodjava/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;

      6: checkcast     #4                  // class SexEnum

      9: areturn

 

 static {};

   Code:

      0: new           #4                  // class SexEnum

      3: dup

      4: ldc           #7                  // String GIRL

      6: iconst_0

      7: invokespecial #8                 // Method "<init>":(Ljava/lang/String;I)V

     10: putstatic     #9                  // Field GIRL:LSexEnum;

     13: new           #4                  // class SexEnum

     16: dup

     17: ldc           #10                 // String BOY

     19: iconst_1

     20: invokespecial #8                 // Method "<init>":(Ljava/lang/String;I)V

     23: putstatic     #11                 // Field BOY:LSexEnum;

     26: iconst_2

     27: anewarray     #4                  // class SexEnum

     30: dup

     31: iconst_0

     32: getstatic     #9                  // Field GIRL:LSexEnum;

     35: aastore

     36: dup

     37: iconst_1

     38: getstatic     #11                 // Field BOY:LSexEnum;

     41: aastore

     42: putstatic     #1                  // Field $VALUES:[LSexEnum;

     45: return

}

很明显,静态代码块对应的代码完成了对成员GIRL和BOY的初始化工作。好久没有看过JVM字节码,都忘光了,想明白上字节码的语义,请自行阅读《Java虚拟机说明书》

 

结论:通过定义枚举,可以保证需要使用该枚举的地方,参数一定是该枚举的成员,同时增强代码的可读性。enum不过是Java语言为我们提供的一个语法糖[1](什么是语法糖?),方便我们定义常量。通过enum关键字定义的实际上是一个类,只不过编译器会保证这个类继承自Enum,并且会给这个类自动的加入一些成员。

 

[1] 语法糖:就是在编译器层面对Java语法的改动,并没有改动JVM,即字节码的结构并没有改变。Java中的语法糖还有:泛型,增强的for等。

 

个人的浅薄理解,欢迎转载,转载注明出处http://blog.csdn.net/u014495327/article/details/42043823。by hoolee。

 

 

 

Java enum枚举是怎么回事