Java枚举类型

目录

一、前言:

二、枚举类型:

三、底层原理

四、应用

应用一:定义常量

底层原理详解

应用二:添加新方法

应用三:与switch结合使用

应用四:实现接口

应用五:使用接口组织枚举


一、前言

回想单例设计模式:单例类是一个类只有一个实例,那么多例类就是一个类有多个实例,但不是无限个数的实例,而是有限个数的实例,这才能是枚举类。 枚举类是把变量的值一一列出来,变量的值只限于列举出来的值的范围内。

Java枚举类型_第1张图片

二、枚举类型

  1. 在Java中,被 enum 关键字修饰的类型就是枚举类型,enum 的全称为 enumeration,它是 JDK 1.5 中引入的新特性。所有的枚举类型都是继承自Enum 类型。 
  2. 它是一种特殊的数据类型,之所以特殊是因为它既是一种类(class)类型却又比类类型多了些特殊的约束,因此这些约束的存在也造就了枚举类型的简洁性、安全性以及便捷性。
  3. 枚举一般用于以下情况:定义常量、添加新方法、与switch结合使用、实现接口、使用接口组织枚举。

     下面使用枚举定义常量,并对比未使用枚举定义常量的区别,同时介绍枚举的基本原理。

三、底层原理

     见底层原理详解。

四、应用

   应用一:定义常量

    案例:未使用枚举类型定义常量

    我们通常利用public final static 方法定义的代码如下,分别用1-6表示星期一到星期日

public class EnumWeekDay {

    public static final int MONDAY =1;

    public static final int TUESDAY=2;

    public static final int WEDNESDAY=3;

    public static final int THURSDAY=4;

    public static final int FRIDAY=5;

    public static final int SATURDAY=6;

    public static final int SUNDAY=7;
    
    public static void main(String[] args) {
      System.out.println(EnumWeekDay .MONDAY);
      System.out.println(EnumWeekDay .WEDNESDAY);
      System.out.println(EnumWeekDay .THURSDAY);
      System.out.println(EnumWeekDay .FRIDAY);
      System.out.println(EnumWeekDay .SATURDAY);
      System.out.println(EnumWeekDay .SUNDAY);
    }

}

问题:上述的常量定义常量的方式称为int枚举模式,这样的定义方式在类型安全和使用方便性上有不足之处,如果存在定义int值相同的变量,混淆的几率很大,编译器也不会提出任何警告。
解决方案:使用枚举类型
      枚举类型现后上述int枚举模式并不提倡,相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法,现在我们利用枚举类型来重新定义上述的常量。

      案例:使用枚举类型之后定义常量

enum EnumWeekDay {
    //使用枚举方式,会自动赋值,默认值是从0开始
    MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

进行测试:

public class WeekDayDemo {
    public static void main(String[] args) {
         //结果本质上都是EnumWeekDay对象,底层相当于调用了EnumWeekDay默认构造方法创建一个对象,将所有的数据存入数组
        System.out.println(EnumWeekDay.MONDAY.getClass().getName());
        System.out.println(EnumWeekDay.MONDAY);
        System.out.println(EnumWeekDay.TUESDAY);
        System.out.println(EnumWeekDay.WEDNESDAY);
        System.out.println(EnumWeekDay.THURSDAY);
        System.out.println(EnumWeekDay.FRIDAY);
        System.out.println(EnumWeekDay.SATURDAY);
        System.out.println(EnumWeekDay.SUNDAY);
        System.out.println(EnumWeekDay.SUNDAY);

        System.out.println(EnumWeekDay.MONDAY.ordinal());
        System.out.println(EnumWeekDay.TUESDAY.ordinal());
        System.out.println(EnumWeekDay.WEDNESDAY.ordinal());
        System.out.println(EnumWeekDay.THURSDAY.ordinal());
        System.out.println(EnumWeekDay.FRIDAY.ordinal());
        System.out.println(EnumWeekDay.SATURDAY.ordinal());
        System.out.println(EnumWeekDay.SUNDAY.ordinal());
    }
}

运行结果

com.JavaSe.emum.EnumWeekDay
星期一
星期二
星期三
星期四
星期五
星期六
星期日
0
1
2
3
4
5
6

       通过案例可以看出,使用枚举的结果本质上底层调用了EnumWeekDay默认构造方法,创建了多个EnumWeekDay实例对象,对象起名分别为MONDAY到SUNDAY,将枚举数据实例存入一个数组的里面,ordinal是数组的下标。(后面原理部分会讲)

       案例:使用枚举的有参构造

步骤:

  1. 先定义枚举实例序列,枚举实例后的括号,表示调用私有构造方法;
  2. 必须在enum实例序列的最后添加一个分号;
  3. 创建私有变量;
  4. 编写私有有参构造方法;
  5. 覆盖toString()方法

public enum EnumWeekDay {
    //1、定义枚举常量, 2、并添加分号
    MONDAY("星期一"), TUESDAY("星期二"), WEDNESDAY("星期三"),
    THURSDAY("星期四"), FRIDAY("星期五"), SATURDAY("星期六"), SUNDAY("星期日");

    // 3、创建私有变量;
    private String weekday;

    //4、编写私有有参构造方法;
    private EnumWeekDay(String weekday) {
        System.out.println(weekday);
        this.weekday = weekday;
    }
    //5、覆盖toString()方法
    @Override
    public String toString() {
        return this.weekday;
    } 

}

运行结果

星期一
星期二
星期三
星期四
星期五
星期六
星期日

底层原理详解

       实际上在使用关键字enum创建枚举类型并编译后,编译器会为我们生成一个相关的类,
这个类继承了Java API中的java.lang.Enum类。以上面案例为例:使用javac进行编译EnumWeekDay.java:javac EnumWeekDay.java,生成EnumWeekDay.class,对EnumWeekDay.class反编译如下:

public enum EnumWeekDay  {

   MONDAY("星期一"), 
   TUESDAY("星期二"), 
   WEDNESDAY("星期三"),
   THURSDAY("星期四"), 
   FRIDAY("星期五"), 
   SATURDAY("星期六"), 
   SUNDAY("星期日");
   
   private String weekday;
   
   // $FF: synthetic field
   private static final EnumWeekDay[] $VALUES 
           = new EnumWeekDay[]{MONDAY, TUESDAY, WEDNESDAY,
             THURSDAY, FRIDAY, SATURDAY, SUNDAY};

   private EnumWeekDay(String var3) {
      System.out.println(var3);
      this.weekday = var3;
   }

   public String toString() {
      return this.weekday;
   }
}

再进一步分析:

final class EnumWeekDay extends Enum {
    private String weekday;
    //私有构造函数
    private EnumWeekDay(String name)
    {
      this.weekday =weekday;
    }

    //前面定义的7种枚举实例
    public static final EnumWeekDay MONDAY;
    public static final EnumWeekDay TUESDAY;
    public static final EnumWeekDay WEDNESDAY;
    public static final EnumWeekDay THURSDAY;
    public static final EnumWeekDay FRIDAY;
    public static final EnumWeekDay SATURDAY;
    public static final EnumWeekDay SUNDAY;
    private static final EnumWeekDay  $VALUES[];

    static
    {
        //实例化枚举实例
        MONDAY = new EnumWeekDay("星期一");
        TUESDAY = new EnumWeekDay("星期二");
        WEDNESDAY = new EnumWeekDay("星期三");
        THURSDAY = new EnumWeekDay("星期四");
        FRIDAY = new EnumWeekDay("星期五");
        SATURDAY = new EnumWeekDay("星期六");
        SUNDAY = new EnumWeekDay("星期日");
        $VALUES = (new EnumWeekDay[] {
                MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
        });

    }

    //编译器为我们添加的静态的values()方法
    public static EnumWeekDay[] values()
    {
        return (EnumWeekDay[])$VALUES.clone();
    }
    //编译器为我们添加的静态的valueOf()方法,注意间接调用了Enum也类的valueOf方法
    public static EnumWeekDay valueOf(String s)
    {
        return (EnumWeekDay)Enum.valueOf(./EnumWeekDay, s);
    }

}

       从反编译的代码看出,EnumWeekDay类(注意该类是final类型的,将无法被继承)继承自java.lang.Enum类,同时编译器还帮助我们生成了7个EnumWeekDay类型的实例对象分别对应枚举中定义的7个日期,充分说明了使用关键字enum定义的EnumWeekDay类型中的每种日期枚举常量也是实实在在的EnumWeekDay实例对象。

        类中values()方法的作用就是获取枚举类中的所有变量,并作为数组返回,valueOf()根据参数获取1个对应枚举变量,测试用例如下: 

for (EnumWeekDay weekDay:EnumWeekDay.values()) {
    System.out.println(weekDay);
}

System.out.println(EnumWeekDay.valueOf("MONDAY"));

应用二:添加新方法

   Java 为枚举类型提供了一些内置的方法,同时枚举常量也可以有自己的方法。此时要注意必须在枚举实例的最后一个成员后添加分号,而且必须先定义枚举实例。

步骤:

  1. 先定义枚举实例序列,枚举实例后的括号,表示调用私有构造方法;
  2. 必须在enum实例序列的最后添加一个分号;
  3. 创建私有变量;
  4. 编写私有有参构造方法;
  5. 添加新方法;
  6. 覆盖toString()方法。

public enum EnumWeekDay {
    //1、定义枚举常量, 2、并添加分号
    MONDAY("星期一"), TUESDAY("星期二"), WEDNESDAY("星期三"),
    THURSDAY("星期四"), FRIDAY("星期五"), SATURDAY("星期六"), SUNDAY("星期日");
    // 3、创建私有变量;
    private String weekday;

    //4、编写私有有参构造方法;
    private EnumWeekDay(String weekday) {
        System.out.println(weekday);
        this.weekday = weekday;
    }
    //5、覆盖toString()方法
    @Override
    public String toString() {
        return this.weekday;
    }
    //6、添加新方法
    public static EnumWeekDay getWeekDay(int num) {
         switch(i) {
            case 1:
                return EnumWeekDay.MONDAY;
            case 2:
                return EnumWeekDay.TUESDAY;
            case 3:
                return EnumWeekDay.WEDNESDAY;
            case 4:
                return EnumWeekDay.THURSDAY;
            case 5:
                return EnumWeekDay.FRIDAY;
            case 6:
                return EnumWeekDay.SATURDAY;
            case 7:
                return EnumWeekDay.SUNDAY;
            default:
                System.out.println("wrong number!");
                return null;
        }
    }
}

class EnumWeekDayDemo{
    public static void main(String[] args) {
        System.out.println(EnumWeekDay.getWeekDay(1).toString());
        System.out.println(EnumWeekDay.getWeekDay(2).toString());
        System.out.println(EnumWeekDay.getWeekDay(3).toString());
        System.out.println(EnumWeekDay.getWeekDay(4).toString());
        System.out.println(EnumWeekDay.getWeekDay(5).toString());
        System.out.println(EnumWeekDay.getWeekDay(6).toString());
        System.out.println(EnumWeekDay.getWeekDay(7).toString());
    }
}
运行结果

星期一
星期二
星期三
星期四
星期五
星期六
星期日

应用三:与switch结合使用

       关于使用switch进行条件判断时,条件参数一般只能是整型,字符型。而枚举型确实也被switch所支持,在java 1.7后switch也对字符串进行了支持。这里我们简单看一下switch与枚举类型的使用:

public enum EnumWeekDay {
    //1、定义枚举常量, 2、并添加分号
    MONDAY("星期一"), TUESDAY("星期二"), WEDNESDAY("星期三"),
    THURSDAY("星期四"), FRIDAY("星期五"), SATURDAY("星期六"), SUNDAY("星期日");
    // 3、创建私有变量;
    private String weekday;

    //4、编写私有有参构造方法;
    private EnumWeekDay(String weekday) {
        System.out.println(weekday);
        this.weekday = weekday;
    }
    //5、覆盖toString()方法
    @Override
    public String toString() {
        return this.weekday;
    }  
}

与switch结合测试类:

public class WeekDayDemo {
    public static void main(String[] args) {
        EnumWeekDay weekDay = EnumWeekDay .MONDAY;
        getDay(weekDay);
    }

    public static void getDay(EnumWeekDay weekDay){
        switch (weekDay){
            case MONDAY:
                System.out.println(MONDAY);
                break;
            case TUESDAY:
                System.out.println(TUESDAY);
                break;
            case WEDNESDAY:
                System.out.println(WEDNESDAY);
                break;
            case THURSDAY:
                System.out.println(THURSDAY);
                break;
            case FRIDAY:
                System.out.println(FRIDAY);
                break;
            case SATURDAY:
                System.out.println(SATURDAY);
                break;
            case SUNDAY:
                System.out.println(SUNDAY);
                break;
            default:
                System.out.println("输入有误");
                break;
        }
    }
}

应用四:实现接口

       由于Java单继承的原因,enum类并不能再继承其它类,但并不妨碍它实现接口,因此enum类同样是可以实现多接口的,如下:

interface food{
    void eat();
}

interface sport{
    void run();
}

public enum EnumDemo2 implements food ,sport{
    FOOD,
    SPORT,
    ; //分号分隔

    @Override
    public void eat() {
        System.out.println("eat.....");
    }

    @Override
    public void run() {
        System.out.println("run.....");
    }

    public static void main(String[] args) {
        EnumDemo2.FOOD.eat();
        EnumDemo2.SPORT.run();
    }
}

应用五:使用接口组织枚举

       有时候,我们可能需要对一组数据进行分类,比如对食物分类,食物包含dessert(点心)、Coffee等,而且希望这些都属于food类型,此时可以利用接口来组织,因此利用一个枚举嵌套枚举的方式,可以统一管理食物中的数据了。如下(代码引用自Thinking in Java):

public interface Food {  
    enum Coffee implements Food{  
        BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO  
    }  
    enum Dessert implements Food{  
        FRUIT, CAKE, GELATO  
    }  
}
public class TypeOfFood {
   public static void main(String[] args) {
      Food food = Dessert.GELATO;
      food = Coffee.CAPPUCCINO;
  }



 

你可能感兴趣的:(java,java)