持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第21天,点击查看活动详情
真正的前言
这一章:枚举 讲的是基础部分的知识。
因本人能力与目前所学知识有限,尚不能完全搞懂、理解其后面的知识还望谅解,如果有解读更好的文章的话,也可以在评论区里粘上链接,大家一起学习,共勉 = ̄ω ̄=o(( >ω<))b 干杯 d((>ω< ))o
枚举
枚举:
是一种由一组固定常量集合组成的类型。
枚举的主要目的是:为了加强编译时类型的安全性。
枚举类型是一种特殊的数据类型,之所以特殊是因为它既是一种类(Class)类型却又比类类型多了些特殊的约束,但是这些约束的存在也造就了枚举类型的简洁性、安全性以及便捷性。
枚举声明
- 定义一个枚举常量
package com.kaf.test_enum;
// 创建一个表示辛辣程度的枚举类
public enum Spiciness {
// 不辣,微辣,中辣,辣,爆辣
NOT, MILD, MEDIUM, HOT, FLAMING
}
PS:定义枚举常量的时候它这里没有加分号哦!!
也不是说我们一定要定义枚举常量,而是定义枚举常量会方便很多。
- 在没有使用枚举常量的情况下,我们一般是如何定义常量呢?
public class Spiciness {
public static final int NOT = 0;
public static final int MILD = 1;
public static final int MEDIUM = 2;
public static final int HOT = 3;
public static final int FLAMING = 4;
}
如上述那样定义常量也没错,但这样存在许多不足。如在类型安全和使用方便性上。如果存在定义 int 值相同的变量,混淆的几率还是很大的,编译器也不会提出任何警告。 因此,当能使用枚举的时候,并不提倡这种写法。
枚举的底层实现
前面也说了,枚举类型是一个特殊的类,每一个枚举项本质上都是枚举类自身的实例
因此,通过 javac 命令将上述的 Spiciness Java文件编译之后得到
我们可以看到:
- 一个枚举类在经过编译器编译之后,变成了一个 final 类,它继承了java.lang.Enum;
- 而枚举中定义的枚举常量,增加了相应的 public static final 属性
- 且其类型变成了自定义的 Spiciness 类(枚举)类型
- 变量名变成了枚举常量的名字
∴ 本质上枚举类型与自定义的常量类型是一样的
因此我们在使用的时候,尽量使用枚举类型,因为它更加方便高效易懂
Enum枚举的常见方法
| 返回类型 | 方法名称 | 方法说明 |
|---|---|---|
| int | compareTo(E o) | 比较此枚举与指定对象的顺序 |
| boolean | equals(Object other) | 当指定对象等于此枚举常量时,返回 true |
| Class<?> | getDeclaringClass() | 返回与此枚举常量的枚举类型相对应的 Class 对象 |
| String | name() | 返回此枚举常量的名称,在其枚举声明中对其进行声明 |
| int | ordinal() | 返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零) |
| String | toString() | 返回枚举常量的名称,它包含在声明中 |
| static<T extends Enum> T | static valueOf(Class enumType, String name) | 返回带指定名称的指定枚举类型的枚举常量。 |
枚举的使用实例
通过上面的反编译我们可以看到,枚举常量本质上就是 public static final的变量(常量)
即 直接将它当作一个变量(常量)来使用即可
package com.kaf.test_enum;
public class SimpleEnumUse {
public static void main(String[] args) {
Spiciness howHot = Spiciness.MEDIUM;
System.out.println(howHot);
}
}
output:
MEDIUM
这里编译器会自动创建一个 toString() 方法,以便你可以很方便地显示某个 enum 实例的名字
① 使用枚举的 ordinal() 方法来遍历输出枚举常量
ordinal()方法用于获取枚举变量在枚举类中声明的顺序,下标从 0 开始,与数组中的下标很相似。 它的设计是用于 EumSet 和 EnumMap 复杂的基于枚举的数据结构使用。
package com.kaf.test_enum;
public class EnumOrder {
public static void main(String[] args) {
// values()方法:按照 enum 常量的声明顺序来产生由这些常量构成的数组
for (Spiciness s : Spiciness.values())
// ① ordinal()方法:用来表示 enum 常量的声明顺序
System.out.println(s + ", ordinal " + s.ordinal());
Spiciness flaming = Spiciness.valueOf("FLAMING");
// valueOf((String name):根据名称获取枚举变量
System.out.println("I can eat " + flaming + " spiciness food.");
}
}
output:
NOT, ordinal 0
MILD, ordinal 1
MEDIUM, ordinal 2
HOT, ordinal 3
FLAMING, ordinal 4
I can eat FLAMING spiciness food.
PS:如果枚举项声明的位置发生了变化,那么 ordinal()方法的值也会随之变化! 所以,尽量避免使用该方法。不然,当枚举项比较多时,别人在中间增删一项,会导致后续的所有顺序发生改变。
② 枚举的 values()
values()方法可以获取枚举类中的所有变量,并作为数组返回
代码同上 orz
package com.kaf.test_enum;
public class EnumOrder {
public static void main(String[] args) {
// ② values()方法:按照 enum 常量的声明顺序来产生由这些常量构成的数组
for (Spiciness s : Spiciness.values())
// ordinal()方法:用来表示 enum 常量的声明顺序
System.out.println(s + ", ordinal " + s.ordinal());
Spiciness flaming = Spiciness.valueOf("FLAMING");
// valueOf((String name):根据名称获取枚举变量
System.out.println("I can eat " + flaming + " spiciness food.");
}
}
注意:values()方法是由编译器插入到枚举类中的 static 方法,而它的父类 Enum 中并不存在这个方法。
③ 枚举的 valueOf((String name)
valueOf(String name)方法与 Enum类中的 valueOf()方法的作用类似
根据名称获取枚举变量,同样是由编译器生成的,但更简洁些,只需传递一个参数。
package com.kaf.test_enum;
public class EnumOrder {
public static void main(String[] args) {
// values()方法:按照 enum 常量的声明顺序来产生由这些常量构成的数组
for (Spiciness s : Spiciness.values())
// ordinal()方法:用来表示 enum 常量的声明顺序
System.out.println(s + ", ordinal " + s.ordinal());
Spiciness flaming = Spiciness.valueOf("FLAMING");
// ③ valueOf((String name):根据名称获取枚举变量
System.out.println("I can eat " + flaming + " spiciness food.");
}
}
output:
NOT, ordinal 0
MILD, ordinal 1
MEDIUM, ordinal 2
HOT, ordinal 3
FLAMING, ordinal 4
I can eat FLAMING spiciness food.
枚举的构造方法
默认情况下,枚举类是不需要构造方法的,
默认的变量就是声明时的字符串。当然,你也可以通过自定义构造方法,来初始化枚举的一些状态信息。
package com.kaf.test_enum;
public enum OzWitch {
// (在使用枚举类型的构造方法的时候)必须在方法之前先定义实例
WEST("Miss Gulch, aka the Wicked Witch of the West"),
NORTH("Glinda, the Good Witch of the North"),
EAST("Wicked Witch of the East, wearer of the Ruby " +
"Slippers, crushed by Dorothy's house"),
SOUTH("Good by inference, but missing");
private String description;
// 构造方法必须是包访问或私有访问
private OzWitch(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public static void main(String[] args) {
for(OzWitch witch : OzWitch.values())
System.out.println(witch + ": " + witch.getDescription());
}
}
output:
WEST: Miss Gulch, aka the Wicked Witch of the West
NORTH: Glinda, the Good Witch of the North
EAST: Wicked Witch of the East, wearer of the Ruby Slippers, crushed by Dorothy's house
SOUTH: Good by inference, but missing
PS:在使用 enmu 的构造方法的时候,需要先定义好 enum 实例!且最后一个 enum 实例需要加上分号!!
调用 enum 实例的方法的方式:
// PS:在上述程序上追加代码如下:
System.out.println(OzWitch.EAST);
System.out.println(OzWitch.valueOf("EAST"));
// 时刻注意 那些枚举值都是实例常量!!!
System.out.println(OzWitch.EAST.getDescription());
switch 语句中的 enum
在 switch 中使用 enum, 是 enum 提供的一项非常便利的功能。一般来说,在 switch 中只能使用整数值,而枚举实例天生就具备整数值的次序,并且可以通过 ordinal()方法取得其次序(显然编译器帮我们做了类似的工作),因此我们可以在 switch 语句中使用 enum。
注意:一般来说我们必须使用一个 enum 类型来修饰一个 enum 实例,但是在 case 中却不用这么做。此时的我们只需要使用 enum 实例所定义的字符串即可
package com.kaf.test_enum;
// 在 switch 语句中的 enum
// 定义一个 enum 类型:
enum Signal { GREEN, YELLOW, RED, }
public class TrafficLight {
Signal color = Signal.RED;
public void change() {
switch(color) {
// 注意:一般来说我们必须使用一个 enum 类型来修饰一个 enum 实例,但是在 case 中却不用这么做
// 所以这里不用 Signal.RED, 而是使用 RED、GREEN、YELLOW(如果使用 Signal.RED 会报错)
case RED:
color = Signal.GREEN;
break;
case GREEN:
color = Signal.YELLOW;
break;
case YELLOW:
color = Signal.RED;
break;
}
}
// 修改 enum 中的 toString() 方法
public String toString() {
return "The traffic light is " + color;
}
public static void main(String[] args) {
TrafficLight t = new TrafficLight();
for(int i = 0; i < 7; i++) {
System.out.println(t);
t.change();
}
}
}
PS:其实说白了,在 switch 语句中使用 enum 需要注意:case块中不用再用 enum 类型来修饰一个 enum 实例了
后话(想看的就看吧...反正八成也没人看...):
我对于枚举类型理解的还不是很深入,只到这部分...(这部分其实也就只是入门基础罢了...)
其实后面还有 EnumSet、EnumMap 以及 enum 的职责链等等...
那些知识以目前的水平我尚且不能理解,更不可能硬写出来了...orz如果有人感兴趣的话,可以去翻下我下面的参考文章,自我感觉还蛮有价值的,蛮有用的