Java 有两种方式定义新类型:类和接口。
对于大部分面向对象编程来说,这两种方法够了,但是对于一些特殊情况比如:想定义一个 Color 类,它只能有 Red、Green、Blue 3种值,其他的任何值都是非法的,这种情况就适用枚举简单方便。
所谓的枚举就是限制一个类的对象产生范围
其他知识可以参考:
一、基本概念
已经知道使用 eunm 关键字可以定义一个枚举,该关键字表示的是 java.lang.Enum
类型,即使用 enum 声明的枚举类型就相当于定义一个类,此类默认继承 java.lang.Enum
类。
java.lang.Enum
的定义:
public abstract class Enum<E extends Enum<E>> extends Object
implements Comparable<E>,java.io.Serializable
从定义可看出该类实现了 Comparable 和 Serializable 接口,证明枚举可以使用比较器和序列化操作
枚举类的主要操作方法:
枚举类名建议带上Enum后缀,枚举成员名称需要全大写,单词间用下划线隔开
枚举其实就是特殊的常量类,切构造方法被默认强制是私有
例如:
枚举名字:DealStatusEnum
成员名称:SUCCESS / UNKNOWN_REASON
二、取得枚举的信息
在枚举类建立完成后,实际上都会为其调用枚举类中的构造方法,为其赋值。在 Enum 类的构造方法中的第一个参数 name 就是定义的枚举的名称,第二个参数 ordinal 则会从 0 开始依次进行编号,之后可以使用 Enum 类总提供的 name()
和 ordinal()
方法取得名称和编号
enum Color{
RED,GREEN,BLUE;//定义枚举的3个类型
}
public class Test{
public static void main(String[] args) {
for (Color c:Color.values()){//枚举.values() 表示得到全部枚举的内容
System.out.println(c.ordinal() + "-->" + c.name());
}
}
}
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
三、为每一个枚举对象属性赋值
如果要为enum定义方法,那么必须在enum的最后一个实例尾部添加一个分号。此外,在enum中,必须先定义实例,不能将字段或方法定义在实例前面。否则,编译器会报错。
1. 通过构造方法为属性赋值
每个枚举类中都有其指定好的若干对象,当然每一个枚举对象中也可以包含多个属性,这些属性可以通过构造方法为其赋值
enum Color{
RED("红色"),GREEN("绿色"),BLUE("蓝色");//定义枚举的3个类型
private Color(String name){
this.setName(name);
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Test{
public static void main(String[] args) {
for (Color c:Color.values()){//枚举.values() 表示得到全部枚举的内容
System.out.println(c.ordinal() + "-->" + c.name() + c.getName());
}
}
}
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
程序中在定义的 Color 枚举类中设置了一个 name属性,并且通过构造方法设置 name 属性的内容。
因为 Color 中已经明确地写出了有一个参数的构造方法,所以在声明枚举内容时必须调用这个构造方法,这样在定义枚举内容时必须使用如下的语句形式:
RED("红色"),GREEN("绿色"),BLUE("蓝色");
- 1
或者:
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;
}
}
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
2. 通过 setter方法为属性赋值
也可以通过调用 setter() 方式为指定的属性赋值,但是这样必须明确每一个枚举类的对象,如果操作的对象时 RED,则名字应该为“红色”;如果操作的对象是GREEN,则名字应该为“绿色”等。
enum Color{
RED,GREEN,BLUE;//定义枚举的3个类型
private String name;
public String getName(){
return name;
}
public void setName(String name) {
switch (this){
case RED:{
if ("红色".equals(name)){
this.name = name;
}else System.out.println("设置内容错误。");
break;
}
case GREEN:{
if ("绿色".equals(name)){
this.name = name;
}else System.out.println("设置内容错误。");
break;
}
case BLUE:{
if ("蓝色".equals(name)){
this.name = name;
}else System.out.println("设置内容错误。");
break;
}
}
}
}
public class Root{
public static void main(String[] args) {
Color c = Color.BLUE;
c.setName("兰色");//设置一个错误的名字
c.setName("蓝色");//设置一个正确的名字
System.out.println(c.getName());
}
}
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
代码中首先通过枚举类取得了里面的一个对象,之后开始为期设置内容。
四、使用比较器
在 Enum 类的定义中已经实现好了 Comparable 接口,所以枚举类的内容本身是可以进行排序的,可以通过 TreeSet 进行枚举的排序操作
enum Color {
RED, GREEN, BLUE;//定义枚举的3个类型
}
public class Root{
public static void main(String[] args) {
Set<Color> t = new TreeSet<Color>();//只能加入 Color 类型
t.add(Color.GREEN);
t.add(Color.BLUE);
t.add(Color.RED);
Iterator<Color> iter = t.iterator();//使用迭代输出
while (iter.hasNext()) {
System.out.print(iter.next() + "、");
}
}
}
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
这里加入的顺序和输出的信息不一致,证明已经被排序了,是使用Enum 类中的 ordinal 属性排序的
枚举类型对象之间的值比较,是可以使用==
,直接来比较值,是否相等的,不是必须用equals
五、枚举的原理
实际上在使用关键字 enum 创建枚举类型并编译后,编译器会为我们生成一个相关的类,这个类继承了Java API中的java.lang.Enum
类,
也就是说通过关键字 enum 创建枚举类型在编译后事实上也是一个类类型而且该类继承自java.lang.Enum
类。
从反编译的代码可以看出编译器确实帮助我们生成了一个Color类而且该类继承自java.lang.Enum
类,该类是一个抽象类,
除此之外,编译器还帮助我们生成了3个Color类型的实例对象分别对应枚举中定义的3个颜色。
还为我们生成了两个静态方法,分别是values()
和 valueOf()
,
到此我们也就明白了,使用关键字enum定义的枚举类型,在编译期后,也将转换成为一个实实在在的类,而在该类中,会存在每个在枚举类型中定义好常量的对应实例对象,如上述的RED
枚举类型对应public static final Day RED