参考:java技术手册
参考:https://blog.csdn.net/testcs_dn/article/details/78604547
java有两种特殊形式的类型,在java类型系统中扮演着特定的角色。这两种类型是枚举类 型(enumerated type)和注解类型(annotation type)。
本文介绍枚举。
一、枚举的定义
枚举是类的变种。
假设我们要定义红、黄、蓝色中颜色的枚举,我们可以使用enum关键字定义这个类型:
public enum PrimaryColor {
// 实例列表末尾的分号是可选的
RED, GREEN, BLUE
}
注意:
(1)如上PrimaryColor定义的是一个类型,这个类型是枚举。
(2)枚举内部的REG、GREEN、BLUE实际上是PrimaryColer类型的实例。
通过如下包含成员的枚举类型定义,更好的理解枚举实例的概念:
Java中由于枚举是特殊的类,所以可以拥有成员(字段和方法)。
假设,我们要定义一个枚举,包含前几个正多边形(等边等角的形状),而且想为这些形状指定一些属性(在方法中指定)。我们可以使用接收一个参数的枚举实现这个需求,如下所示:
public enum RegularPolygon {
// 有参数的枚举必须使用分号。由于这些实际上是RegularPolygon的实例,所以可以传入 “构造方法” 参数。
TRIANGLE(3), SQUARE(4), PENTAGON(5), HEXAGON(6);
private Shape shape;
public Shape getShape() {
return shape;
}
private RegularPolygon(int sides) {
switch (sides) {
case 3:
// 假设这些形状的构造方法接收的参数是边长和角度
shape = new Triangle(1,1,1,60,60,60);
break;
case 4:
shape = new Rectangle(1,1);
break;
case 5:
shape = new Pentagon(1,1,1,1,1,108,108,108,108,108);
break;
case 6:
shape = new Hexagon(1,1,1,1,1,1,120,120,120,120,120,120);
break;
}
}
}
注意,如上:
(1)如果字段或方法有主体,那么实例列表后面必须加上分号。
(2)如上样例中,枚举实例(TRIANGLE、SQUARE、PENTAGON、HEXAGON)具有参数,所以要显式提供构造函数。枚举实例由Java运行时创建,在创建TRIANGLE、SQUARE、PENTAGON、HEXAGON实例时,调用RegularPlygon ()构造方法,分别传入2、4、5、6入参,为这几个枚举实例分配内存空间和赋值。本质上每个枚举实例包含一个shape字段和2个方法。
(3)枚举实例由Java运行时创建,其不可在枚举外部进行实例化,所以把构造方法声明为私有方法。
(4)枚举有如下特殊性:
• 都(隐式)扩展 java.lang.Enum 类;(所以不可继承其他类)
• 不能泛型化;
• 可以实现接口;
• 不能被扩展子类;
• 只能有一个私有(或使用默认访问权限)的构造方法。
• 所有的枚举值默认都是 public static final 的。
二、枚举引入的版本
enum类型是java1.5引入的。
三、枚举类型的使用
(1)类似常量的方式使用
支持枚举之前,常量只能通过public static fianl方式定义。
引入枚举后,可以使用枚举实现类似常量方式的代码使用。如:
public enum PrimaryColor {
// 实例列表末尾的分号是可选的
RED, GREEN, BLUE
}
PrimaryColor类型的REG、GREEN、BLUE实例可以按照静态字段的方式引用:PrimaryColor.RED、PrimaryColor. GREEN 和 PrimaryColor.BLUE。
(2)配合switch使用
如:
enum Signal {
GREEN, YELLOW, RED
}
public class TrafficLight {
Signal color = Signal.RED;
public void change() {
switch (color) {
case RED:
color = Signal.GREEN;
break;
case YELLOW:
color = Signal.RED;
break;
case GREEN:
color = Signal.YELLOW;
break;
}
}
}
(3)配合for循环遍历枚举中的实例
private enum SimpleEnum {
SPRING, SUMMER, AUTUMN, WINTER
}
public class EnumTest {
/**
* 循环枚举,输出ordinal属性;若枚举有内部属性,则也输出。(说的就是我定义的TYPE类型的枚举的typeName属性)
*/
private static void forEnum() {
for (SimpleEnum simpleEnum : SimpleEnum.values()) {
System.out.println(simpleEnum + " ordinal " + simpleEnum.ordinal());
}
}
}
打印结果是:
SPRING ordinal 0
SUMMER ordinal 1
AUTUMN ordinal 3
WINTER ordinal 4
注:
(1)如上ordinal是继承自 java.lang.Enum 类的int类型字段。
(2)如上println打印中simpleEnum参数会自动调用java.lang.Enum类型从Object中继承的toString()方法转换。
(3)Java编译器自动在enum类型中插入一些方法,其中就包括values()。所以在enum类型中并没有实现values()方式,程序在没编译的时候,自然就没法查看values()方法的源码。
(4)枚举中自定义方法、和覆盖继承自enum类型的方法
enum类型本质上是类,可以自定义方法和覆盖继承的方法。
public enum Color {
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
// 普通方法
public static String getName(int index) {
for (Color c : Color.values()) {
if (c.getIndex() == index) {
return c.name;
}
}
return null;
}
// get set 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
@Override
public String toString() {
returnthis.index+"_"+this.name;
}
}
public class EnumTest {
......
private static void forEnum() {
for (Color color : Color.values()) {
System.out.println("color = " + color + " color.name = " + color.getName() + " color.index = " + color.getIndex());
}
}
......
}
(5)枚举实例的比较
枚举本质上是类型,枚举实例本质上是对象。所以枚举类型对象之间的比较也采用equals方法。但是呢,同class类型对象的不同是,==在class类型的比较中实际上比较的是两个引用是否指向同一对象;==在做枚举类型对象比较时,是比较对象的值是否相等,可替代equals()方法。
(6)枚举可以通过implements关键字继承接口
使用方式同class继承接口。
(7)枚举集合
java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumSet保证集合中的元素不重复;EnumMap中的 key是enum类型,而value则可以是任意类型。关于这个两个集合可以参考JDK文档。