一、何为枚举
枚举类型是一种特殊的数据类型(常用的数据类型比如字符串、整型),这种数据类型的变量值限定在固定的范围, 比如季节只有春夏秋冬,一个年的 12 个月份。Java 枚举类使用 enum 关键字来定义,各个常量使用逗号 , 来分割。
定义一个星期的枚举类, 代码可以简洁如下:
package com.enjoy.base.annatation.source;
public enum Week {
Monday, Tuesday, Wednesday,Thursday,Friday,Saturday;
}
使用实例
enum Color
{
RED, GREEN, BLUE;
}
public class Test
{
// 执行输出结果
public static void main(String[] args)
{
Color c1 = Color.RED;
System.out.println(c1);
}
}
内部类中使用枚举
枚举类也可以声明在内部类中:
public class Test
{
enum Color
{
RED, GREEN, BLUE;
}
// 执行输出结果
public static void main(String[] args)
{
Color c1 = Color.RED;
System.out.println(c1);
}
}
迭代枚举元素
enum Color
{
RED, GREEN, BLUE;
}
public class MyClass {
public static void main(String[] args) {
for (Color myVar : Color.values()) {
System.out.println(myVar);
}
}
}
在枚举类中直接列出常量,常量遵循全部大写的规则。在上面的枚举类示例代码中,Monday, Tuesday, Wednesday,Thursday,Friday,Saturday 是Week的成员。
- 枚举成员默认是final、public、static (所以可以使用Week.Monday方式调用枚举成员)
- 每一个枚举类型成员都可以看作是枚举类的实例 (Week.Monday的类型也是Week)
二、枚举类的特性
- 枚举可以实现接口,但不能继承接口,也不能被继承。
- 枚举类是final的,所以不能继承。
- 枚举类的构造方法是私有的
- 枚举成员是静态、final和public
- 枚举成员是枚举类的实例
三、枚举类实现的原理
枚举类型的奥秘就在编译阶段,枚举类在编译后会生成了一个扩展java.lang.Enum的类。这个可以通过JDK自带的javap工具来反编译生成的.class文件。对上面的生成的Week.class文件进行反编译
- -p参数的意思是反编译代码中包含私有的方法, p是private的意思。 从控制台输出的反编译后的源码可以看出:
- 自定义的枚举类会自动继承java.lang.Enum类
- 每个成员变量都会被转换为 private static final的枚举类型的实例
- 自动添加private的构造函数 从反编译后的源码就不难理解Enum的特性了。
四、枚举的常见用法
- 常量 在JDK1.5 之前,定义常量都是: public static final.... ,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法
public enum Color {
RED, GREEN, BLANK, YELLOW
}
- switch JDK1.6之前的switch语句只支持int,char类型,使用枚举,能让我们的代码可读性更强。
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;
}
}
}
- 向枚举中添加新方法
如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。 而且 Java 要求必须先定义 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;
}
}
- 覆盖枚举的方法 下面给出一个toString()方法覆盖的例子。
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;
}
//覆盖方法
@Override
public String toString() {
return this.index+"_"+this.name;
}
}
- 实现接口 所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。
public interface Behaviour {
void print();
String getInfo();
}
public enum Color implements Behaviour{
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;
}
//接口方法
@Override
public String getInfo() {
return this.name;
}
//接口方法
@Override
public void print() {
System.out.println(this.index+":"+this.name);
}
}
- 使用接口组织枚举
public interface Food {
enum Coffee implements Food{
BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO
}
enum Dessert implements Food{
FRUIT, CAKE, GELATO
}
}
- 关于枚举集合的使用
import java.util.EnumMap;
import java.util.EnumSet;
public class LightTest {
// 1.定义枚举类型
public enum Light {
// 利用构造函数传参
RED(1), GREEN(3), YELLOW(2);
// 定义私有变量
private int nCode;
// 构造函数,枚举类型只能为私有
private Light(int _nCode) {
this.nCode = _nCode;
}
@Override
public String toString() {
return String.valueOf(this.nCode);
}
}
/**
*
* @param args
*/
public static void main(String[] args) {
// 1.遍历枚举类型
System.out.println("演示枚举类型的遍历 ......");
testTraversalEnum();
// 2.演示EnumMap对象的使用
System.out.println("演示EnmuMap对象的使用和遍历.....");
testEnumMap();
// 3.演示EnmuSet的使用
System.out.println("演示EnmuSet对象的使用和遍历.....");
testEnumSet();
}
/**
*
* 演示枚举类型的遍历
*/
private static void testTraversalEnum() {
Light[] allLight = Light.values();
for (Light aLight : allLight) {
System.out.println("当前灯name:" + aLight.name());
System.out.println("当前灯ordinal:" + aLight.ordinal());
System.out.println("当前灯:" + aLight);
}
}
/**
*
* 演示EnumMap的使用,EnumMap跟HashMap的使用差不多,只不过key要是枚举类型
*/
private static void testEnumMap() {
// 1.演示定义EnumMap对象,EnumMap对象的构造函数需要参数传入,默认是key的类的类型
EnumMap<Light, String> currEnumMap = new EnumMap<Light, String>(
Light.class);
currEnumMap.put(Light.RED, "红灯");
currEnumMap.put(Light.GREEN, "绿灯");
currEnumMap.put(Light.YELLOW, "黄灯");
// 2.遍历对象
for (Light aLight : Light.values()) {
System.out.println("[key=" + aLight.name() + ",value="
+ currEnumMap.get(aLight) + "]");
}
}
/**
*
* 演示EnumSet如何使用,EnumSet是一个抽象类,获取一个类型的枚举类型内容<BR/>
*
* 可以使用allOf方法
*/
private static void testEnumSet() {
EnumSet<Light> currEnumSet = EnumSet.allOf(Light.class);
for (Light aLightSetElement : currEnumSet) {
System.out.println("当前EnumSet中数据为:" + aLightSetElement);
}
}
}
/*
*
* 演示枚举类型的遍历 ......
当前灯name:RED
当前灯ordinal:0
当前灯:1
当前灯name:GREEN
当前灯ordinal:1
当前灯:3
当前灯name:YELLOW
当前灯ordinal:2
当前灯:2
演示EnmuMap对象的使用和遍历.....
[key=RED,value=红灯]
[key=GREEN,value=绿灯]
[key=YELLOW,value=黄灯]
演示EnmuSet对象的使用和遍历.....
当前EnumSet中数据为:1
当前EnumSet中数据为:3
当前EnumSet中数据为:2
*
*
*
*/
注:
-
1.枚举类名建议带上Enum后缀,枚举成员名称需要全大写,单词间用下划线隔开
-
2.枚举其实就是特殊的常量类,且狗子方法被默认强制是私有
-
3.正例: TestEnum; 成员名称:SUCCESS /UNKOWN-REASON*
参考: