枚举类型
一、概念
An enum type is a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it.
枚举类型是一种特殊数据类型,能够为一个变量定义一组预定义的常量。变量必须等于为其预定义的值之一。
枚举类中声明的每一个枚举值代表枚举类的一个实例对象。
Java中的枚举是一种特殊的数据类型,用于表示一组相关的常量,这些常量具有固定的值和名称。枚举常量通常用于表示一些固定的、不可变的选项,例如颜色、方向、星期几、操作状态等。
Java枚举类型可以让我们在代码中使用更加清晰、可读的名称来表示某些常量,从而提高代码的可读性、可维护性和可重用性。
二、枚举的演变
1、数据合法性验证–正则
第一:封装学生
public class Student {
//姓名
private String name ;
//等级:必须只能是 A B C D E 五种级别
private String grade ; //ABCDE
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
if(!grade.matches("[ABCDE]")) {
throw new RuntimeException("等级只能是A B C D E") ;
}
this.grade = grade;
}
@Override
public String toString() {
return "姓名:"+this.name + ",等级:"+this.grade;
}
}
第二:测试
public class MainTest {
public static void main(String[] args) {
Student stu = new Student() ;
stu.setName("张三");
stu.setGrade("G");
System.out.println(stu);
}
}
2、改进,对象实现
把等级封装为一个类
第一:封装等级
public class Grade {
private String value ;
// 私有化构造方法,不允许在类外实例化对象
private Grade() {}
private Grade(String value) {
this.value = value ;
}
// 实现化五个对象
public static final Grade A = new Grade("优秀");
public static final Grade B = new Grade("良好");
public static final Grade C = new Grade("中等");
public static final Grade D = new Grade("合格");
public static final Grade E = new Grade("不合格");
@Override
public String toString() {
return this.value;
}
}
第二:重新封装学生对象,引用Grade对象
public class Student {
// 姓名
private String name ;
// 等级:必须只能是 A B C D E 五种级别
private Grade grade ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Grade getGrade() {
return grade;
}
public void setGrade(Grade grade) {
this.grade = grade;
}
@Override
public String toString() {
return "姓名:"+this.name + ",等级:"+this.grade;
}
}
第三:测试
public class MainTest {
public static void main(String[] args) {
Student stu = new Student() ;
stu.setName("张三");
stu.setGrade(Grade.B);
System.out.println(stu);
}
}
3、改进,枚举实现
把等级封装为一个枚举类,JDK5新增enum关键字,用于定义一个枚举类,枚举类也可以有构造方法(私有)、字段和方法。
第一:定义枚举类
1)简单定义
// 定义Grade枚举
enum Grade {
// 枚举值:各枚举值表示枚举的实例对象(默认是静态的)
A,B,C,D,E;
}
说明:此处的Grade枚举与上面的Grade类功能一样,枚举值A,B,C,D,E就是此枚举的实例对象(而且是静态的),也就是说:枚举类中声明的每一个枚举值代表枚举类的一个实例对象。
2)改进Grade枚举—指定A、B、C、D、E五个等级对应的中文表示
public enum Grade {
// 定义枚举列表值,同时使用构造方法初始化属性
A("优秀"),B("良好"),C("中等"),D("合格"),E("不合格");
// 定义属性:表示等级ABCDE对应的中文表示
private String value ;
// 定义构造方法
private Grade(String value) {
this.value = value ;
}
// 重写 toString 方法
@Override
public String toString() {
return this.value;
}
}
3)改进Grade枚举—指定A、B、C、D、E五个等级的分数范围
public enum Grade {
/**
* 创建枚举列表值,并且使用构造方法初始化属性;
* 同时,由于枚举类中定义了抽象方法,不能直接创建枚举值,
* 因此,创建枚举值时,必须以匿名内部类方式创建
* 而且在匿名内部类中重写方法,实现返回该等级对应的分数范围
*/
A("优秀"){
@Override
public String getScoreRange() {
return "分数>=90 && 分数<=100";
}
},B("良好"){
@Override
public String getScoreRange() {
return "分数>=80 && 分数<90";
}
},C("中等"){
@Override
public String getScoreRange() {
return "分数>=70 && 分数<80";
}
},D("合格"){
@Override
public String getScoreRange() {
return "分数>=60 && 分数<70";
}
},E("不合格"){
@Override
public String getScoreRange() {
return "分数>=0 && 分数<60";
}
};
// 定义属性:表示等级ABCDE对应的中文表示
private String value ;
/**
* 构造方法
* @param value
*/
private Grade(String value) {
this.value = value ;
}
/**
* 定义抽象方法
* @return 返回不同等级对应的分数范围
*/
public abstract String getScoreRange() ;
// 重写 toString()方法,输出等级的中文表示
@Override
public String toString() {
return this.value;
}
/**
* 定义成员方法
*/
public void sayHello() {
System.out.println("成员方法");
}
/**
* 定义静态方法
*/
public static void testStatic() {
System.out.println("静态方法");
}
}
以下是使用抽象类来实现和以上枚举类同样的功能
public abstract class Grade {
//定义属性:表示等级ABCDE对应的中文表示
private String value ;
/**
* 构造方法:设置各等级的中文表示
* @param value
*/
private Grade(String value) {
this.value = value ;
}
//创建抽象类实现对象,通过匿名类实现抽象类,并实现方法
public static Grade A = new Grade("优秀") {
@Override
public String getScoreRange() {
return "分数>=90 && 分数<=100";
}
};
public static Grade B = new Grade("良好") {
@Override
public String getScoreRange() {
return "分数>=80 && 分数<90";
}
};
public static Grade C = new Grade("中等") {
@Override
public String getScoreRange() {
return "分数>=70 && 分数<80";
}
};
public static Grade D = new Grade("合格") {
@Override
public String getScoreRange() {
return "分数>=60 && 分数<70";
}
};
public static Grade E = new Grade("不合格") {
@Override
public String getScoreRange() {
return "分数>=0 && 分数<60";
}
};
/**
* 抽象方法
* @return 返回不同等级对应的分数范围
*/
public abstract String getScoreRange() ;
//重写toString()方法,输出等级的中文表示
@Override
public String toString() {
return this.value;
}
}
第二:封装学生对象,引用Grade枚举
与上例中的Student类一样,不需要做任何改动。验证了Grade枚举类与上例的Grade类功能一样。
第三:测试
public class MainTest {
public static void main(String[] args) {
// 创建学生对象并初始化数据
Student stu = new Student() ;
stu.setName("张三");
stu.setGrade(Grade.B);
// 输出学生信息
System.out.println(stu);
// 获取学生的等级,并打印输出该等级的分数范围
Grade g = stu.getGrade();
System.out.println("分数范围:" + g.getScoreRange());
// 调用枚举成员方法
g.sayHello();
// 调用枚举静态方法
Grade.testStatic();
}
}
三、语法
[访问修饰符] enum 枚举类名 {
// 枚举常量 - 枚举实例(枚举值)
// 成员变量、常量
// 成员方法、抽象方法、静态方法、重载方法、重写方法
// 构造方法
}
要点:
1)枚举是特殊的类(常量类),在声明枚举类时,可以定义成员变量、方法和构造方法
- 枚举常量是枚举类型的实例,它们是不可变的、公共的、静态的和最终的。
- 构造方法必须私有的。
2)枚举实例必须要求先定义,也就说,枚举值必须定义在枚举类的第一行代码中;
3)规范
- 命名规范:全大写命名,多个单词间使用下划线分隔
- 注释规范:所有的枚举类型字段必须要有注释,说明每个数据项的用途
4)各个枚举值逗号分隔,枚举类中仅仅只有枚举值,则可以省略分号,否则必须显式写分号
5)不能泛型化
// 错误
public enum Color<T> {
...
}
说明:Java 枚举类型并不支持泛型。这是因为枚举类型是在编译时确定的,而泛型是在运行时确定的。
6)使用枚举常量
语法:枚举类名.枚举常量
7)枚举API方法
四、要点
1、添加新的方法
public enum Color {
RED("红"),GREEN("绿"),BLUE("蓝");
private String value ;
private Color(String value) {
this.value = value ;
}
// 添加成员方法
public String getValue() {
return value;
}
}
2、重写方法
public enum Color {
RED("红"),GREEN("绿"),BLUE("蓝");
private String value ;
private Color(String value) {
this.value = value ;
}
// 添加成员方法
public String getValue() {
return value;
}
// 重写方法
public String toString() {
return this.value;
}
}
3、switch的支持
JDK5中扩展了switch语句,它除了可以接收int,byte,char,short外,还可以接收一个枚举类型。
//1)定义枚举
public enum Color {
RED,GREEN,BLUE
}
//2)测试 -- switch对枚举的支持
public class MainTest {
public static void main(String[] args) {
Color week = Color.RED;
switch(week) {
case RED:
System.out.println("红");break;
case GREEN:
System.out.println("绿");break;
case BLUE:
System.out.println("蓝");break;
}
}
}
4、Enum常用方法
枚举类型都隐式继承了java.lang.Enum类,因此不能继承其他类,但可以实现接口。
Java中声明的枚举类,均是java.lang.Enum类的子类,它继承了Enum类的所有方法。
public enum Color {
RED("红"),GREEN("绿"),BLUE("蓝");
private String value ;
private Color(String value) {
this.value = value ;
}
public String getValue() {
return value;
}
}
1)name()
返回枚举常量的名称,正是因为在其枚举声明中声明。
Color color = Color.RED;
String name = color.name();
System.out.println(name); // 输出:RED
2)valueOf(String name)
根据枚举常量名称,返回枚举实例
Color color = Color.valueOf("RED");
System.out.println(color.getValue()); // 输出:红
3)values()
遍历枚举类所有的枚举值
Color[] colors = Color.values();
for (Color color : colors) {
System.out.println(color.name());
}
/*
输出:
RED
GREEN
BLUE
*/
注意:神秘的values()方法和valueOf(String)方法,这两个方法在其父类Enum中并不存在,那么它们哪里来的呢?答案是:它们是在创建枚举实例时,由编译器添加的static方法。
4)valueOf(Class enumType, String name)
此方法返回具有指定名称的指定枚举类型的枚举常量
Color color = Enum.valueOf(Color.class,"RED");
System.out.println(color.getValue());
区别valueOf(String name)与valueOf(Class enumType, String name)。前者是编译器添加的静态方法,后者是继承自Enum类的静态方法。
5)ordinal()
返回此枚举常量的序数(其枚举声明中的位置,其中初始常量被分配一个序号零)
Color color = Color.RED;
int ordinal = color.ordinal();
System.out.println(ordinal); //输出:0
6)compareTo()
比较两个枚举值常量序数之差
Color color = Color.RED;
int n = color.compareTo(Color.BLUE) ; //0 减 2
System.out.println(n); //输出:-2
五、应用案例
public enum ResponseCode {
SUCCESS(200,"成功"),
ILLEGAL_ARGUMENT(401,"无效参数"),
NEED_LOGIN(403,"权限不够"),
ERROR(500,"服务器错误");
private final int code;
private final String desc;
ResponseCode(int code,String desc){
this.code = code;
this.desc = desc;
}
public int getCode(){
return code;
}
public String getDesc(){
return desc;
}
}
在开发中枚举可以用来定义常量