文章目录

  • 一.什么是枚举?
  • 二.枚举的创建
  • 三.枚举对象的常用方法介绍
  • 四.枚举应用场景
  • 1.枚举类当做常量类使用
  • 2.枚举类在switch语句中使用
  • 3.枚举类中定义普通方法
  • 4.枚举类中定义抽象方法
  • 5.枚举类实现接口
  • 6.使用接口对枚举类分类
  • 7.实现单例
  • 五.枚举实现的原理


一.什么是枚举?

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

二.枚举的创建

  • 将类用 关键字 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

该方法可以将枚举类型成员以数组的形式返回

四.枚举应用场景

1.枚举类当做常量类使用
public enum StateType {
	/**
	 * 成功返回状态
	 */
	OK(200, "OK"),

	/**
	 * 请求格式错误
	 */
	BAD_REQUEST(400, "bad request"),
	/**
	 * 未授权
	 */
	UNAUTHORIZED(401, "unauthorized"),
	/**
	 * 没有权限
	 */
	FORBIDDEN(403, "forbidden"),

	/**
	 * 请求的资源不存在
	 */
	NOT_FOUND(404, "not found"),
	/**
	 * 该http方法不被允许
	 */
	NOT_ALLOWED(405, "method not allowed"),
	/**
	 * 请求处理发送异常
	 */
	PROCESSING_EXCEPTION(406, "Handling Exceptions"),
	/**
	 * 
	 * 请求处理未完成
	 */
	PROCESSING_UNFINISHED(407, "To deal with unfinished"),

	/**
	 * 登录过期
	 */
	BEOVERDUE(408, "Be overdue"),

	/**
	 * 用户未登录
	 */
	NOT_LOGIN(409, "Not logged in"),

	/**
	 * 这个url对应的资源现在不可用
	 */
	GONE(410, "gone"),
	/**
	 * 请求类型错误
	 */
	UNSUPPORTED_MEDIA_TYPE(415, "unsupported media type"),
	/**
	 * 校验错误时用
	 */
	UNPROCESSABLE_ENTITY(422, "unprocessable entity"),
	/**
	 * 请求过多
	 */
	TOO_MANY_REQUEST(429, "too many request");

	private int code;
	private String value = null;

	private StateType(int code, String value) {
		this.code = code;
		this.value = value;
	}

	public String value() {	return this.value;	}
	public int getCode() {return code;	}

}
2.枚举类在switch语句中使用

switch语句支持的类型有如下几种:

  • 基本数据类型: byte、short、char、int
  • 包装数据类型: Byte、Short、Character、Integer
  • 枚举类型: Enum
  • 字符串类型: String(jdk7+ 开始支持)
//周一到周天枚举
enum WeekEnum {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

//jdk1.7开始switch语句开始支持String类型,而jdk1.6之前只支持int,char,enum类型,使用枚举的话,能使代码的可读性大大增强
public class WeekTest {
    public static void main(String[] args) {
        WeekEnum week = WeekEnum.MONDAY;
        switch (week) {
            case MONDAY:
                System.out.println("星期一");
                break;
            case TUESDAY:
                System.out.println("星期二");
                break;
            case WEDNESDAY:
                System.out.println("星期三");
                break;
            case THURSDAY:
                System.out.println("星期四");
                break;
            case FRIDAY:
                System.out.println("星期五");
                break;
            case SATURDAY:
                System.out.println("星期六");
                break;
            case SUNDAY:
                System.out.println("星期日");
                break;
            default:
                System.out.println("null");
        }
    }
}
3.枚举类中定义普通方法

在定义枚举时不只是可以定义多个参数,还可以定义其他的普通方法

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
//广东
4.枚举类中定义抽象方法

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

可以通过枚举类抽象方法来实现策略模式

案例1

public enum Operation {
    PLUS {
        // 实例中实现抽象方法
        public double apply(double x, double y) {
            return x + y;
        }
    },
    MINUS {
        public double apply(double x, double y) {
            return x - y;
        }
    };

    // 声明抽象方法
    public abstract double apply(double x, double y);
}
//调用
//double result = Operation.PLUS.apply(1, 2);

案例2

enum PayrollDay {
	//工作日与周末计算每天工资的策略枚举
    MONDAY(PayType.WEEKDAY), 
    TUESDAY(PayType.WEEKDAY), 
    WEDNESDAY( PayType.WEEKDAY), 
    THURSDAY(PayType.WEEKDAY), 
    FRIDAY(PayType.WEEKDAY), 
    SATURDAY(PayType.WEEKEND), 
    SUNDAY(PayType.WEEKEND);
	
	//工作计算策略 
    private final PayType payType;
    PayrollDay(PayType payType) {
        this.payType = payType;
    }
    
	//工作时间(小时),考勤率
    double pay(double hoursWorked, double payRate) {
        return payType.pay(hoursWorked, payRate);
    }

    // 策略枚举
    private enum PayType {
    	//工作日策略
        WEEKDAY {
       		 //工作时间(小时),考勤率
            double overtimePay(double hours, double payRate) {
                return hours <= HOURS_PER_SHIFT 
                	? 0
                	: (hours - HOURS_PER_SHIFT)  * payRate / 2;
            }
        },
        //周末策略
        WEEKEND {
        	//工作时间(小时),考勤率
            double overtimePay(double hours, double payRate) {
                return hours * payRate / 2;
            }
        };
        
        //每天工作小时数
        private static final int HOURS_PER_SHIFT = 8;
        
        // 声明抽象方法-加班费计算
        //工作时间(小时),考勤率
        abstract double overtimePay(double hrs, double payRate);

        //工作时间(小时),考勤率
        double pay(double hoursWorked, double payRate) {
            double basePay = hoursWorked * payRate;
            return basePay + overtimePay(hoursWorked, payRate);
        }
    }

	//测试案例	
    public static void main(String[] args) {
    	System.out.println("时薪100的人在周五工作8小时的收入:" + PayrollDay.FRIDAY.pay(8.0, 100));
    	System.out.println("时薪100的人在周六工作8小时的收入:" + PayrollDay.SATURDAY.pay(8.0, 100));
	}
}

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

5.枚举类实现接口

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

创建一个接口

public interface Show {
    void show();
}

四季枚举类实现该接口并重写方法

public enum Season implements Show {
    SPRING("春天"),
    SUMMER("夏天"),
    AUTUMN("秋天"),
    WINTER("冬天");

    private final String seasonName;

    Season(String seasonName) {
        this.seasonName = seasonName;
    }

    public String getSeasonName() {
        return seasonName;
    }

    @Override
    public void show() {
        System.out.println("向往四季如春");
    }
}

我们使用每一个枚举类都可以调用show方法,而打印的结果也都是“向往四季如春”

Season.WINTER.show();//向往四季如春

我们不管使用哪一个枚举成员时,调用的show方法都是同一个。所以,我们在实现接口后,可以这样重写方法,如下:

public enum Season1 implements Show {
    SPRING("春天") {
        @Override
        public void show() {
            System.out.println("春天是个踏青的季节");
        }
    },
    SUMMER("夏天") {
        @Override
        public void show() {
            System.out.println("夏天是个炎热的季节,我要吃冰棍");
        }
    },
    AUTUMN("秋天") {
        @Override
        public void show() {
            System.out.println("秋天还算是凉爽");
        }
    },
    WINTER("冬天") {
        @Override
        public void show() {
            System.out.println("冬天的雪还不错,就是有点冷");
        }
    };

    private final String seasonName;

    Season1(String seasonName) {
        this.seasonName = seasonName;
    }

    public String getSeasonName() {
        return seasonName;
    }
}

我们在枚举成员的后面加了{},而重写的方法可以写在各个枚举成员中,这样就接触了上述所有的那个限制。这下,我们使用哪个枚举成员对象调用show方法都是不同的。

同样也可以通过枚举类实现接口来实现策略模式

6.使用接口对枚举类分类

使用接口对枚举分类,我们需要创建一个接口容器,里面存放着此接口容器所存放的多个枚举类,然后将各个枚举类实现此接口,以这样的方式可实现对枚举分类。代码如下,打印结果放在了代码后面的注释中:

public interface Weeks {
    //工作日
    enum WorkingDay implements Weeks {
        MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY
    }

    //双休日
    enum Weekend implements Weeks {
        SATURDAY, SUNDAY
    }
}

class WeeksTest {
    public static void main(String[] args) {
        System.out.print("双休日:");
        for (Weeks.Weekend weekend : Weeks.Weekend.values()) {
            System.out.print(weekend + " ");        //双休日:SATURDAY SUNDAY
        }

        //换行
        System.out.println();

        System.out.print("工作日:");
        for (Weeks.WorkingDay workingDay : Weeks.WorkingDay.values()) {
            System.out.print(workingDay + " ");     //工作日:MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY
        }

        //换行
        System.out.println();

        Weeks.WorkingDay friday = Weeks.WorkingDay.FRIDAY;
        System.out.println("星期五:" + friday);      //星期五:FRIDAY
    }
}

java 枚举 下标 java中枚举_常量

7.实现单例

五.枚举实现的原理

实际上在枚举类被编译后,编译器会为我们生成一个对应的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