Java枚举类型探究

1,907 阅读5分钟

一、何为枚举

枚举类型是一种特殊的数据类型(常用的数据类型比如字符串、整型),这种数据类型的变量值限定在固定的范围, 比如季节只有春夏秋冬,一个年的 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文件进行反编译

002.png

  • -p参数的意思是反编译代码中包含私有的方法, p是private的意思。 从控制台输出的反编译后的源码可以看出:
  • 自定义的枚举类会自动继承java.lang.Enum类
  • 每个成员变量都会被转换为 private static final的枚举类型的实例
  • 自动添加private的构造函数 从反编译后的源码就不难理解Enum的特性了。

003.png

四、枚举的常见用法

  1. 常量 在JDK1.5 之前,定义常量都是: public static final.... ,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法
public enum Color {  
  RED, GREEN, BLANK, YELLOW  
} 
  1. 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;  
        }  
    }  
}  
  1. 向枚举中添加新方法

如果打算自定义自己的方法,那么必须在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;  
    }  
}  
  1. 覆盖枚举的方法 下面给出一个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;  
    }  
}  
  1. 实现接口 所有的枚举都继承自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);  
    }  
}  
  1. 使用接口组织枚举
public interface Food {  
    enum Coffee implements Food{  
        BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO  
    }  
    enum Dessert implements Food{  
        FRUIT, CAKE, GELATO  
    }  
}  
  1. 关于枚举集合的使用
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*

参考:

blog.csdn.net/u010002184/…

www.runoob.com/java/java-e…

blog.csdn.net/mingyuli/ar…