【Java基础】分析Java1.5新特性-枚举

一.什么是枚举?

在java编程过程中,我们通常需要定义一些固定数量的常量,在java1.5以前,通常的做法是定义一个静态常量类,但自jdk1.5后,java引入了枚举(关键字enum,全称为 enumeration,值类型),在枚举中,我们可以把相关的常量分组到一个枚举类型里,枚举也比常量类有更多灵活的用法,使用枚举,可以有效的提高代码的整洁性、可读性、可维护性等等

二.枚举的创建

  • 将类用 关键字 enum 修饰
  • 枚举类中的数据每个枚举对象使用,隔开,最后一个枚举对象使用;结束。
  • 可以在枚举类中声明属性, 自定义方法

三.enum 对象的常用方法介绍

方法 描述
int compareTo(E o) 比较此枚举与指定对象的顺序。
Class getDeclaringClass() 返回与此枚举常量的枚举类型相对应的 Class 对象。
String name() 返回此枚举常量的名称,在其枚举声明中对其进行声明。
int ordinal() 该方法获取的是枚举变量在枚举类中声明的顺序,下标从0开始
String toString() 返回枚举常量的名称,它包含在声明中。
static <T extends Enum> T valueOf(Class enumType, String name) 返回带指定名称的指定枚举类型的枚举常量。可以实现将普通字符串转换为枚举实例
values 该方法可以将枚举类型成员以数组的形式返回

四.枚举用法

enum类当做常量类使用
//周一到周天枚举
public enum WeekEnum {
    MON,TUES,WED,THURS,FRI,SAT,SUN;
}

//jdk1.7开始switch语句开始支持String类型,而jdk1.6之前只支持int,char,enum类型,使用枚举的话,能使代码的可读性大大增强
public class TestEnum {
    public static void main(String[] args) {
        WeekEnum week = WeekEnum.TUES;
        switch (week) {
            case MON:
                System.out.println("星期一");
                break;
            case TUES:
                System.out.println("星期二");
                break;
            case WED:
                System.out.println("星期三");
                break;
            case THURS:
                System.out.println("星期四");
                break;
            case FRI:
                System.out.println("星期五");
                break;
            case SAT:
                System.out.println("星期六");
                break;
            case SUN:
                System.out.println("星期天");
                break;
        }
    }
}
enum类中自定义方法处理枚举实例
enum AddressEnum {
    HUNAN("湖南", "1101"),
    GUANGDONG("广东", "1102"),
    SICHUANG("四川", "1103"),
    JIANGXI("江西", "1104"),;

    private String address;
    private String code;

    private AddressEnum(String address, String code) {
        this.address = address;
        this.code = code;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public  static String getAddressName(String addressCode){
        for(AddressEnum  addressEnum : AddressEnum.values()){
            if(addressEnum.getCode().equals(addressCode)){
                return  addressEnum.getAddress();
            }
        }
        return  null;
    }

    public  static String getAddressCode(String addressName){
        for(AddressEnum  addressEnum : AddressEnum.values()){
            if(addressEnum.getAddress().equals(addressName)){
                return  addressEnum.getCode();
            }
        }
        return  null;
    }

    public static void main(String[] args) {
        System.out.println(AddressEnum.GUANGDONG.getAddress());
        System.out.println(AddressEnum.GUANGDONG.getCode());
        System.out.println( AddressEnum.getAddressCode("湖南"));
        System.out.println( AddressEnum.getAddressName("1102"));
    }
}

//打印
//广东
//1102
//1101
//广东
enum类中定义抽象方法

与抽象类一样,enum类允许我们为其定义抽象方法,然后使每个枚举实例都实现该方法,以便产生不同的行为方式,注意abstract关键字对于枚举类来说并不是必须的如下:

public enum EnumDemo {

    FIRST{
        @Override
        public String getInfo() {
            return "FIRST TIME";
        }
    },
    SECOND{
        @Override
        public String getInfo() {
            return "SECOND TIME";
        }
    }

    ;

    /**
     * 定义抽象方法
     * @return
     */
    public abstract String getInfo();
    

    //测试
    public static void main(String[] args){
        System.out.println("F:"+EnumDemo.FIRST.getInfo());
        System.out.println("S:"+EnumDemo.SECOND.getInfo());
        /**
         输出结果:
         F:FIRST TIME
         S:SECOND TIME
         */
    }
}

也可以在枚举中定义多个抽象方法, 因枚举类中有多少个抽象方法,枚举实例就要实现多少个,否则编译报错

enum类与接口

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

interface food{
    void eat();
}

interface sport{
    void run();
}

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

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

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

有时候,我们可能需要对一组数据进行分类,比如进行食物菜单分类而且希望这些菜单都属于food类型,appetizer(开胃菜)、mainCourse(主菜)、dessert(点心)、Coffee等,每种分类下有多种具体的菜式或食品,此时可以利用接口来组织,如下

public enum Meal{
  APPETIZER(Food.Appetizer.class),
  MAINCOURSE(Food.MainCourse.class),
  DESSERT(Food.Dessert.class),
  COFFEE(Food.Coffee.class);
  private Food[] values;
  
  private Meal(Class<? extends Food> kind) {
    //通过class对象获取枚举实例
    values = kind.getEnumConstants();
  }
  
  public interface Food {
    enum Appetizer implements Food {
      SALAD, SOUP, SPRING_ROLLS;
    }
    enum MainCourse implements Food {
      LASAGNE, BURRITO, PAD_THAI,
      LENTILS, HUMMOUS, VINDALOO;
    }
    enum Dessert implements Food {
      TIRAMISU, GELATO, BLACK_FOREST_CAKE,
      FRUIT, CREME_CARAMEL;
    }
    enum Coffee implements Food {
      BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,
      LATTE, CAPPUCCINO, TEA, HERB_TEA;
    }
  }
}

现在我们利用一个枚举嵌套枚举的方式,把前面定义的菜谱存放到一个Meal菜单中,通过这种方式就可以统一管理菜单的数据了。

五.枚举实现的原理

实际上在枚举类被编译后,编译器会为我们生成一个对应的class类,且这个类继承java.lang.Enum类

//位于EnumDemo.java文件
public class EnumDemo {

    public static void main(String[] args){
        //直接引用
        Day day =Day.MONDAY;
    }

}
//定义枚举类型
enum Day {
    MONDAY, TUESDAY, WEDNESDAY,THURSDAY, FRIDAY, SATURDAY, SUNDAY;
}

利用javac编译的EnumDemo.java文件后分别生成了Day.class和EnumDemo.class文件,而Day.class就是枚举类型,这验证前面所说的枚举类被编译后,编译器会自动帮助我们生成一个与枚举类相关的class类。

我们再来看看反编译Day.class文件:

//反编译Day.class
final class Day extends Enum{
    //编译器为我们添加的静态的values()方法
    public static Day[] values(){
        return (Day[])$VALUES.clone();
    }
    
    //编译器为我们添加的静态的valueOf()方法,注意间接调用了Enum也类的valueOf方法
    public static Day valueOf(String s) {
        return (Day)Enum.valueOf(com/zejian/enumdemo/Day, s);
    }
    
    //私有构造函数
    private Day(String s, int i){
        super(s, i);
    }
     //前面定义的7种枚举实例
    public static final Day MONDAY;
    public static final Day TUESDAY;
    public static final Day WEDNESDAY;
    public static final Day THURSDAY;
    public static final Day FRIDAY;
    public static final Day SATURDAY;
    public static final Day SUNDAY;
    private static final Day $VALUES[];

    static  {    
        //实例化枚举实例
        MONDAY = new Day("MONDAY", 0);
        TUESDAY = new Day("TUESDAY", 1);
        WEDNESDAY = new Day("WEDNESDAY", 2);
        THURSDAY = new Day("THURSDAY", 3);
        FRIDAY = new Day("FRIDAY", 4);
        SATURDAY = new Day("SATURDAY", 5);
        SUNDAY = new Day("SUNDAY", 6);
        $VALUES = (new Day[] {
            MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
        });
    }
}
  1. 从反编译的代码可以看出编译器确实生成了一个Day类(该类是final类型的,将无法被继承)且该类继承自java.lang.Enum类
  2. 该类是一个抽象类,除此之外编译器还生成了7个Day类型的实例对象分别对应枚举中定义的7个日期
  3. 这说明了我们使用关键字enum定义的Day类型中的每种日期枚举常量都是Day实例对象,只不过对象属性值不一样。 同时编译器还生成了两个静态方法,分别是values()和 valueOf(),用于获取枚举实例对象。
  4. 因此,使用关键字enum定义的枚举类型,在编译期后将转换成为class类,在该类中,会存在每个在枚举类型中定义好变量的对应实例对象,且每个对象都是final修饰的不可变对象。如上述的MONDAY枚举类型对应public static final Day MONDAY
发布了62 篇原创文章 · 获赞 109 · 访问量 5289

猜你喜欢

转载自blog.csdn.net/qq877728715/article/details/103146895