Java基础19--枚举

1 枚举

1.1 什么是枚举类

Java 枚举是一个特殊的类,一般表示一组常量。
enum 的全称为 enumeration, 是 JDK5 中引入的特性。
除了不能继承,基本上可以将 enum 看做一个常规的类。

public enum Week {
   //这类的变量
   MONDAY(0,"星期一"),
   TUESDAY(1,"星期二"),
   WEDNESDAY(2,"星期三"),
   THURSDAY(3,"星期四"),
   FRIDAY(4,"星期五"),
   SATURDAY(5,"星期六"),
   //最后一个类型必须要用分号结束
   SUNDAY(6,"星期日");

   private int num;
   private String desc;

   /**
    * 构造方法必然是private修饰的
    * 就算不写,也是默认的
    *
    * @param num
    * @param desc
    */
   private Week(int num, String desc) {
       this.num=num;
       this.desc = desc;
   }
   public String getDesc() {
       return desc;
   }

   public int getNum() {
       return num;
   }

1)使用enum定义的枚举类默认继承了java.lang.Enum,实现了java.lang.Comparable接口,且不能继承其他类,也不可以被继承。但枚举类可以实现一个或多个接口。
2)枚举类的所有实例必须放在第一行显示,不需使用new,不需显示调用构造方法,每个变量都是public static final修饰的,最终以分号结束。在之后的反编译中,我们就可以理解枚举类其实也是颗语法糖。
3)枚举类的构造方法是私有的,默认的就是private,定义的时候不加也没事。
4)switch()参数可以使用enum。
5)非抽象枚举类默认是final的但定义的时候加上final却编译不通过。我们通过后续的反编译可以得到验证。
6)枚举类可以有抽象方法,但是必须在它的实例中实现。

1.2 为什么要用枚举类

1)出于类型安全考虑,没用枚举类之前,常用静态常量来表示。
比如对于性别的表示,
public static final int MAN = 0;
public static final int WOMAN = 1;
这样的性别定义实际上是一个整型数据,其一,这些变量完全可用来做加减运算,当然我们原意并非如此;其二,意义不明,当我们debug的时候,本来向输出‘男’,结果输出0。于是我们不得不去前面寻找0表示的意义,特别是看别人的代码时,会很懵逼。

2)代码更优雅
一个大一些的程序里面,可能要用到成百上千的静态常量,如果全写在一个文件里面,容易造成命名混淆,程序读起来也比较麻烦。

3)枚举类能方便我们定义自己想要的类型
枚举便于记忆和使用,并且相当于一个接口。使用时只需要封装内部的数据类型,并且限定数据域。而且对于不同的枚举变量,可以调用不同的处理方法(实现枚举类的抽象方法可以做到这一点)。

1.3 含有抽象方法的枚举类

如果写抽象方法,枚举类的所有实例必须实现抽象方法。

/**
 * 枚举类可以有抽象方法,但是必须在它的实例中实现
 */
public enum AbstractWeek {

    MONDAY(0,"星期一") {
        @Override
        public AbstractWeek getNextDay() {
            return TUESDAY;
        }
    }, TUESDAY(1,"星期二") {
        @Override
        public AbstractWeek getNextDay() {
            return WEDNESDAY;
        }
    }, WEDNESDAY(2,"星期三") {
        @Override
        public AbstractWeek getNextDay() {
            return THURSDAY;
        }
    }, THURSDAY(3,"星期四") {
        @Override
        public AbstractWeek getNextDay() {
            return FRIDAY;
        }
    }, FRIDAY(4,"星期五") {
        @Override
        public AbstractWeek getNextDay() {
            return SATURDAY;
        }
    }, SATURDAY(5,"星期六") {
        @Override
        public AbstractWeek getNextDay() {
            return SUNDAY;
        }
    }, SUNDAY(6,"星期日") {
        @Override
        public AbstractWeek getNextDay() {
            return MONDAY;
        }
    };

    private int num;
    private String desc;

    AbstractWeek(int num,String desc) {
        this.num = num;
        this.desc=desc;
    }

    //一个抽象方法
    public abstract AbstractWeek getNextDay();

    public static void main(String[] args) {
        String nextDay=AbstractWeek.MONDAY.getNextDay().toString();
        System.out.println(nextDay);
    }
}

编译后所有实例都会成为内部类,相当于每个实例用匿名内部类的形式实现getNextDay的方法。如:

AbstractWeek MONDAY= new AbstractWeek (){
        @Override
        public AbstractWeek getNextDay() {
            return TUESDAY;
        }
};

1.4 枚举实现原理

这个问题需要从原理角度阐述,我们通过反编译来查看AbstractWeek,可以发现继承了Enum,里面的所有成员变量都是public static final修饰的!而且values()方法是编译器生成的。其实每一个实例都是一个内部类,在项目路径下会生成AbstractWeek$1.class-AbstractWeek$7.class。每个内部类又都实现了getNextDay()方法。因此,定义枚举实例的时候代码如此的优雅,完全是语法糖给我们的甜头呀!

public abstract class AbstractWeek extends java.lang.Enum<AbstractWeek> {
  public static final AbstractWeek MONDAY;

  public static final AbstractWeek TUESDAY;

  public static final AbstractWeek WEDNESDAY;

  public static final AbstractWeek THURSDAY;

  public static final AbstractWeek FRIDAY;

  public static final AbstractWeek SATURDAY;

  public static final AbstractWeek SUNDAY;

  public static solution1.AbstractWeek[] values();
    Code:
       0: getstatic     #2                  // Field $VALUES:[Lsolution1/AbstractWeek;
       3: invokevirtual #3                  // Method "[Lsolution1/AbstractWeek;".clone:()Ljava/lang/Object;
       6: checkcast     #4                  // class "[Lsolution1/AbstractWeek;"
       9: areturn
......
}

1.5 常用方法

在 enum 中,提供了一些基本方法:

values():返回 enum 实例的数组,而且该数组中的元素严格保持在 enum 中声明时的顺序。
name():返回实例名。
ordinal():返回实例声明时的次序,从 0 开始。
getDeclaringClass():返回实例所属的 enum 类型。
equals() :判断是否为同一个对象。

可以使用 == 来比较enum实例。
此外,java.lang.Enum实现了Comparable和 Serializable 接口,所以也提供 compareTo() 方法。

posted @ 2020-12-25 22:23  全栈老刘  阅读(115)  评论(0编辑  收藏  举报