枚举类型
1、枚举类型的概念
先看一个例子。定义一个接口,这个接口用来定义常量:
public interface Common {
public static final String YES = "yes";
public static final String NO = "no";
public static final int MIN_AGE = 18;
public static final int MAX_AGE = 60;
}
测试:
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("请输入你的年龄:");
int age = in.nextInt();
if (age < Common.MIN_AGE || age > Common.MAX_AGE) {
System.out.println("你这个年龄不适合谈恋爱!");
} else if (age >= Common.MIN_AGE && age <= Common.MAX_AGE) {
System.out.println("你恋爱成功了吗?输入yes或no");
String bool = in.next();
if (bool.equals(Common.YES)) {
System.out.println("恭喜你,人生赢家!");
} else if (bool.equals(Common.NO)) {
System.out.println("加油,争取早日脱离光棍!");
}
}
}
控制台:
在接触枚举类型之前,我们定义常量一般都会直接在类或接口中定义。枚举类型可以取代这种定义常量的方式,此外,枚举类型还提供了安全检查功能,本质上其实还是以类的形式存在的。Java枚举是一个特殊的类,一般表示一组常量,比如一年的 4 个季节,一组交通信号灯的颜色等。
api文档说明如下:
2、枚举的定义
枚举类型的定义使用关键字enum,如下:
/*
* 这个枚举类型中定义3种信号等颜色常量
*/
public enum Light {
RED,
YELLOW,
GREEN;
}
RED、YELLOW、GREEN这三个是常量,之间用逗号隔开,最后一个后面是分号。如果引用枚举类型中的常量,比如Light.RED,这个其实是枚举类型的一个实例,这个要注意。以下测试:
public static void main(String[] args) {
List<Light> list = new ArrayList<>();
Light current_light = null;
// 可以看到,枚举类型中的每一个成员变量都是枚举类型的一个实例
list.add(Light.RED);
list.add(Light.GREEN);
list.add(Light.YELLOW);
System.out.println(Light.RED instanceof Light);
Random ran = new Random();
for (int i = 1; i <= 5; i++) {
int res = ran.nextInt(3);
// 信号灯随机跳转
current_light = list.get(res);
if (current_light.equals(Light.RED)) {
System.out.println("现在是红灯,稍等一下!");
} else if (current_light.equals(Light.YELLOW)) {
System.out.println("现在是黄灯,应该视情况决定等待或行驶!");
} else {
System.out.println("现在是绿灯,可以放心通过!");
}
}
}
执行,控制台:
3、枚举类的常用方法
api文档中的所有方法如下:
常用方法说明:
- compareTo(E e):比较两个枚举对象在定义时的顺序,返回0、1、-1。
- name():返回此枚举常量的名称,与其枚举声明中声明的完全相同。
- ordinal():返回枚举成员的位置索引。(按照声明的位置,从0开始)
- toString():返回声明中包含的此枚举常量的名称。
- values():将枚举成员以数组的形式返回。
- valuesOf():将普通字符串转为枚举实例。
代码中测试:
public static void main(String[] args) {
// 将字符串转换为枚举成员
System.out.println(Light.valueOf("RED") == Light.RED);
// 获取枚举成员的数组
Light[] lights = Light.values();
System.out.println("现在枚举类型中的成员数:" + lights.length);
for (int i = 0; i < lights.length; i++) {
System.out.println("枚举名称:" + lights[i].name() + "\t"
+ "枚举值:" + lights[i].toString() + "\t"
+ "所在位置索引:" + lights[i].ordinal() + "\t"
+ "与YELLOW相比的位置:" + lights[i].compareTo(Light.YELLOW));
}
}
控制台:
4、类的内部定义枚举
在一个类的内部也可以定义枚举,像内部类那样:
public class Demo {
// 类的内部定义枚举
enum Letter {
A,B,C,D;
}
// 自定义方法
public static void t0(Letter letter) {
switch (letter) {
case A:
System.out.println("t0方法======>A");
break;
case B:
System.out.println("t0方法======>B");
break;
case C:
System.out.println("t0方法======>C");
break;
case D:
System.out.println("t0方法======>D");
break;
default:
System.out.println("枚举中无此类型!");
break;
}
}
// 测试
public static void main(String[] args) {
Demo.t0(Letter.B);
}
}
控制台:
5、枚举的属性、构造方法、实例方法
枚举跟普通类一样可以用自己的变量、方法和构造函数,构造函数只能使用private访问修饰符,所以外部无法调用。枚举既可以包含具体方法,也可以包含抽象方法。 如果枚举类具有抽象方法,则枚举类的每个实例都必须实现它。
以下通过例子说明。定义枚举类:
public enum Light {
// 枚举成员
RED,
YELLOW,
GREEN;
// 成员属性
private double height;// 信号灯的高度
private int time;// 每种信号的持续时长
// 构造方法修饰符要么不写,要么只能是private
Light() {
}
private Light(double height, int time) {
this.height = height;
this.time = time;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public int getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}
//自定义方法
public String workNormal() {
return "信号灯工作正常!";
}
}
测试:
public static void main(String[] args) {
Light[] lights = Light.values();
// 为枚举实例初始化值
lights[0].setHeight(2.5);
lights[0].setTime(30);
lights[1].setHeight(2.7);
lights[1].setTime(50);
lights[2].setHeight(3.0);
lights[2].setTime(60);
for (int i = 0; i < lights.length; i++) {
System.out.println(lights[i].toString() + "灯高度为:" + lights[i].getHeight()
+ "米,持续" + lights[i].getTime() + "秒," + lights[i].workNormal());
}
}
控制台:
枚举类似普通的类,普通类中属性、方法等在枚举中也能定义,但是枚举的构造方法在外部是不能访问的。
6、枚举的常用用法
以前用枚举的时候,理解为枚举就只是用来定义常量的,后来发现,好像并不只是这样。参考了很多人的博客,了解到枚举常用用法有7种,在这里记录一下。
6.1、定义常量
这是最基本的用法,如下:
public enum Light {
// 枚举成员
RED,
YELLOW,
GREEN;
}
6.2、作为swicth的参数
上面其实用到过了,很早的时候switch只接受基本类型,后来可以支持枚举类型。如下:
public enum Light {
// 枚举成员
RED,
YELLOW,
GREEN;
}
public class Test {
public static void main(String[] args) {
Light light = Light.GREEN;
switch (light) {
case RED:
System.out.println("现在是红灯,等一下吧!");
break;
case GREEN:
System.out.println("现在是绿灯,可以放心行驶!");
break;
case YELLOW:
System.out.println("现在是黄灯,没有车辆再过去吧!");
break;
default:
System.out.println("交通灯坏了!");
break;
}
}
}
6.3、枚举中定义实例方法
这种用法其实就是将枚举当做普通类一样,上面其实演示过了,添加新的方法:
public enum Light {
// 枚举成员
RED,
YELLOW,
GREEN;
// 成员属性
private double height;// 信号灯的高度
private int time;// 每种信号的持续时长
// 构造方法修饰符要么不写,要么只能是private
Light() {
}
private Light(double height, int time) {
this.height = height;
this.time = time;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public int getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}
//自定义方法
public String workNormal() {
return "信号灯工作正常!";
}
}
这里添加了一个workNormal()的成员方法。
public static void main(String[] args) {
Light[] lights = Light.values();
// 为枚举实例初始化值
lights[0].setHeight(2.5);
lights[0].setTime(30);
System.out.println(lights[0].toString() + "灯高度为:" + lights[0].getHeight()
+ "米,持续" + lights[0].getTime() + "秒," + lights[0].workNormal());
}
6.4、覆盖toString方法
其实可以看到,Enum类中只有一个toString方法能重写:
那么就像普通类覆盖toString方法就可以了:
public enum Light {
// 枚举成员
RED,
YELLOW,
GREEN;
@Override
public String toString() {
return "这个toString方法是重写的!";
}
}
public static void main(String[] args) {
System.out.println(Light.GREEN.toString());
}
6.5、实现接口
这种用的比较多,比如开发中自定义错误代码、提示信息等。
接口如下:
public interface ResultCode {
//返回是否操作成功
boolean success();
//返回操作代码
int code();
//返回提示信息
String message();
枚举如下:
/*
* 这个枚举实现接口
*/
public enum CommonCode implements ResultCode {
USERNAME_IS_NULL(false, 10000, "登录名为空!"),
PASSWORD_IS_NULL(false, 10001, "登录密码为空!"),
USERNAME_IS_ERROR(false, 10002, "登录名错误!"),
PASSWORD_IS_ERROR(false, 10003, "登录密码错误!"),
LOGIN_SUCCESS(true, 10004, "登录成功!");
// 成员属性
boolean success;
int code;
String message;
// 枚举的构造方法
private CommonCode(boolean success, int code, String message) {
this.success = success;
this.code = code;
this.message = message;
}
public boolean getSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public boolean success() {
return success;
}
@Override
public int code() {
return code;
}
@Override
public String message() {
return message;
}
@Override
public String toString() {
return "{" + "\n"
+ "\"success\"" + ":" + this.getSuccess() + "," + "\n"
+ "\"code\"" + ":" + this.getCode() + "," + "\n"
+ "\"message\"" + ":" + this.getMessage() + "\n"
+ "}";
}
}
测试:
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("请输入登录名:");
String username = in.next();
if (username.equals("")) {
System.out.println(CommonCode.USERNAME_IS_NULL);
System.exit(0);
}
if (!username.equals("ycz")) {
System.out.println(CommonCode.USERNAME_IS_ERROR);
System.exit(0);
}
System.out.println("请输入登录密码:");
String password = in.next();
if (password.equals("")) {
System.out.println(CommonCode.PASSWORD_IS_NULL);
System.exit(0);
}
if (!password.equals("ycz123456")) {
System.out.println(CommonCode.PASSWORD_IS_ERROR);
System.exit(0);
}
if (username.equals("ycz") && password.equals("ycz123456")) {
System.out.println(CommonCode.LOGIN_SUCCESS);
}
}
控制台:
再执行,然后输入正确的登录名,错误的密码:
再执行,然后输入正确的登录名,正确的密码:
这种枚举实现接口的形式,用的挺多,应该要重点掌握。
6.6、接口来组织枚举
在接口中可定义多个枚举,并且实现该接口。如下:
public interface UnionEnums {
enum E0 implements UnionEnums{
A,B,C,D,E;
}
enum E2 implements UnionEnums{
F,G;
}
enum E3 implements UnionEnums{
H,I,J,K;
}
}
6.7、枚举集合
很少使用,略。