枚举概述

枚举类型是Java 5中新增特性的一部分,它是一种特殊的数据类型,之所以特殊是因为它既是一种类却又比普通类多了些特殊的约束,但是这些约束的存在也造就了枚举类型的简洁性、安全性以及便捷性。

枚举类型的定义

没有枚举类型时定义常量常见的方式:

public class DayDemo {

    public static final int MONDAY =1;

    public static final int TUESDAY=2;

    public static final int WEDNESDAY=3;

    public static final int THURSDAY=4;

    public static final int FRIDAY=5;

    public static final int SATURDAY=6;

    public static final int SUNDAY=7;

}

上述的常量定义常量的方式称为int枚举模式,这样的定义方式并没有什么错,但它存在许多不足,如在类型安全和使用方便性上并没有多少好处,如果存在定义int值相同的变量,混淆的几率还是很大的,编译器也不会提出任何警告,因此这种方式在枚举出现后并不提倡,现在我们利用枚举类型来重新定义上述的常量。

// 枚举类型使用关键字enum定义
enum Day {
    MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

枚举类型的使用

public class EnumDemo {

    public static void main(String[] args){
        //直接引用
        Day day =Day.MONDAY;
    }

}
//定义枚举类型
enum Day {
    MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

枚举实现原理

实际上在使用关键字enum创建枚举类型并编译后,编译器会为我们生成一个继承了java.lang.Enum的类,也就是说通过关键字enum创建枚举类型在编译后事实上也是一个类类型而且该类继承自java.lang.Enum类。下面我们编译前面定义EnumDemo.java并查看生成的class文件来验证这个结论:

//反编译Day.class
final class Day extends Enum
{
    //编译器添加的静态方法values()
    public static Day[] values()
    {
        return (Day[])$VALUES.clone();
    }
    //编译器添加的静态方法valueOf(),注意间接调用了Enum也类的valueOf方法
    public static Day valueOf(String s)
    {
        return (Day)Enum.valueOf(com/test/enumdemo/Day, s);
    }
    
    private Day(String s, int i)
    {
        super(s, i);
    }
    
    public static final Day MONDAY;
    public static final Day TUESDAY;
    public static final Day WEDNESDAY;
    public static final Day THURSDAY;
    public static final Day FRIDAY;
    public static final Day SATURDAY;
    public static final Day SUNDAY;
    private static final Day $VALUES[];

    static 
    {    
        //实例化枚举实例
        MONDAY = new Day("MONDAY", 0);
        TUESDAY = new Day("TUESDAY", 1);
        WEDNESDAY = new Day("WEDNESDAY", 2);
        THURSDAY = new Day("THURSDAY", 3);
        FRIDAY = new Day("FRIDAY", 4);
        SATURDAY = new Day("SATURDAY", 5);
        SUNDAY = new Day("SUNDAY", 6);
        $VALUES = (new Day[] {
            MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
        });
    }
}

枚举的常见方法

Enum抽象类(是所有枚举类的父类)常见方法。

返回类型

方法名称

方法说明

int

compareTo(E o)

比较枚举的大小(根据在枚举类中声明的位置),返回当前对象与对象o位置的差值

boolean

equals(Object other)

当指定对象等于此枚举常量时,返回 true。

Class<?>

getDeclaringClass()

返回与此枚举常量的枚举类型相对应的 Class 对象

String

name()

返回此枚举常量的名称,在其枚举声明中对其进行声明

int

ordinal()

返回枚举常量的序数(在枚举类中声明的位置,从0开始)

String

toString()

返回枚举常量的名称,它包含在声明中

static<T exitnds Enum< T >> T

static valueOf(Class enumType, String name)

返回带指定名称的指定枚举类型的枚举常量。

public class Test {

	public static void main(String[] args) {
		
		// 按照加入顺序,north=0、east=1、south=2、west=3
		Direction north = Direction.NORTH;
		Direction east = Direction.EAST;
		Direction south = Direction.SOUTH;
		Direction west = Direction.WEST;
		
		// values();
		Direction[] directions = Direction.values(); // [NORTH,EAST,SOUTH,WEST]
		
		for(Direction direction: directions) {
			System.out.println(direction);
		}

		//  compareTo
		System.out.println(north.compareTo(west)); //  0-3=-3
		
		// equals
		Direction north2 = Direction.NORTH;
		System.out.println(north2.equals(north)); // true
		System.out.println(north2.equals(east)); // false
		
		// 获取该枚举对象的Class对象引用
		System.out.println(north.getDeclaringClass()); // class com.test.Direction
		
		// name()
		System.out.println(north.name()); //  NORTH
		
		// toString()
		System.out.println(north.toString()); // NORTH
		
		// valueof()
		Direction north3 = Direction.valueOf(Direction.class, "NORTH");
		System.out.println(north3); // NORTH
		
		

	}

}

enum Direction{
	NORTH,
	EAST,
	SOUTH,
	WEST
}

编译器生成的Values()与ValueOf()

  • values():获取一个枚举类中所有的枚举,并以数组形式返回。
  • valueOf(String name):根据名称获取枚举变量。
public class Test {
	
	public static void main(String[] args) {
		// values() 返回枚举类Direction内的所有枚举构成的数组
		Direction[] directions = Direction.values();
		
		for(Direction direction : directions) {
			System.out.println(direction);
		}
		
		// 根据枚举名称返回对应枚举对象
		Direction north = Direction.valueOf("NORTH");
		System.out.println(north);
		
	}

}

enum Direction{
	NORTH,
	EAST,
	SOUTH,
	WEST
}

枚举与Class对象

当枚举实例向上转型为Enum类型后,values()方法将会失效,也就无法一次性获取所有枚举实例变量,但是由于Class对象的存在,即使不使用values()方法,还是有可能一次获取到所有枚举实例变量的,在Class对象中存在如下方法:

返回类型

方法名称

方法说明

T[ ]

getEnumConstants()

返回该枚举类型的所有元素,如果Class对象不是枚举类型,则返回null。

boolean

isEnum()

当且仅当该类声明为源代码中的枚举时返回 true

public class Test {
	
	public static void main(String[] args) {
		
		//正常使用
		Direction[] ds=Direction.values();
		//向上转型Enum
		Enum e = Direction.NORTH;
		//无法调用,没有此方法
		//e.values();
		//获取class对象引用
		Class<?> clasz = e.getDeclaringClass();
		if(clasz.isEnum()) {
			Direction[] dsz = (Direction[]) clasz.getEnumConstants();
		    System.out.println("dsz:"+Arrays.toString(dsz));
		}
		
	}

}

enum Direction{
	NORTH,
	EAST,
	SOUTH,
	WEST
}