文章目录
- 一.什么是枚举?
- 二.枚举的创建
- 三.枚举对象的常用方法介绍
- 四.枚举应用场景
- 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
}
}
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
});
}
}- 从反编译的代码可以看出编译器确实生成了一个Day类
(该类是final类型的,将无法被继承)且该类继承自java.lang.Enum类 - 该类是一个抽象类,除此之外
编译器还生成了7个Day类型的实例对象分别对应枚举中定义的7个日期 - 这说明了我们使用关键字enum定义的Day类型中的每种日期枚举常量都是
Day实例对象,只不过对象属性值不一样。 同时编译器还生成了两个静态方法,分别是values()和 valueOf(),用于获取枚举实例对象。 - 因此,使用关键字enum定义的枚举类型,在编译期后将转换成为class类,在该类中,会存在每个在枚举类型中定义好变量的
对应实例对象,且每个对象都是final修饰的不可变对象。如上述的MONDAY枚举类型对应public static final Day MONDAY
















