欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JDK 5.0(Tiger)中的一些新特性(2):枚举

程序员文章站 2022-07-12 13:30:46
...

JDK 5.0(Tiger)中的一些新特性(2):枚举

 

Last modified:2013-04-06 23:56:12

**********************************************

 

枚举类型:

枚举类型:定义一种类型变量,它指向的值都是固定的。这些值称作枚举的元素,这些元素可以是这个枚举类或者其子类的一个实例对象。该类型的取值只可以是这些元素和null。

 

在没有枚举类型以前我们是怎样实现枚举的功能的呢?

 

下面是我们模拟枚举类型的一个事例:

 

public abstract class WeekDay1 {
	private WeekDay1() {
	}

	public final static WeekDay1 SUN = new WeekDay1() {

		@Override
		public WeekDay1 nextDay() {
			return MON;
		}

	};
	public static final WeekDay1 MON = new WeekDay1() {

		@Override
		public WeekDay1 nextDay() {
			return MON;
		}

	};

	public abstract WeekDay1 nextDay();

	public String toString() {
		return this == SUN ? "SUN" : "MON";
	}
}
   
  JDK 5.0后,我们可以怎样做:
  public enum WeekDay {
  SUN, MON, TUE, WED, THU, FRI, SAT
  }

 

 就像类和接口一样,enum关键字定义了一个新的引用类型。这些值就像static final字段一样(这就是为什么它们的名称一般用都大写来表示),WeekDay可以被指定为这七个值中的任意一个和null,但是不能是其他值。

 

思考:在刚接触到枚举的时候我很不解,既然我们可以自己构造一个和枚举功能相当的类,那么JDK在枚举的升级是不是就是简化操作和代码的升级呢?其实不然,简化操作是一方面,其实更重要的是提供了类型安全性。在5.0之前,我们会可能会使用int 型的1来表示SUN,剩下的以此类推,但是当我们应用weekday时,给一个weekday变量赋值的时候我们如果赋予的是一个大于7的值,那么编译是不会报错的。

 

5.0以前:

public static final int SUN = 1;

如果我们在另外一个地方引用SUN时:

正确的:int day = WeekDay.SUN;

错误但不会报错:int day = 45;

如果打印某个枚举类型,打印出来的就是枚举的字符串本身,与name()方法获得的一样。

 

下面是交通灯的一个枚举事例:

public enum TrafficLamp {
		Red(25) {
			@Override
			public TrafficLamp nextLamp() {
				return Green;
			}
		},
		Yellow(5) {
			@Override
			public TrafficLamp nextLamp() {
				return Red;
			}
		},
		Green(30) {
			@Override
			public TrafficLamp nextLamp() {
				return Yellow;
			}
		};
		public abstract TrafficLamp nextLamp();

		@SuppressWarnings("unused")
		private int time;
  //enum的构造方法必须私有
		private TrafficLamp(int time) {
			this.time = time;
		}
	} 

 

注意思考:枚举只有一个成员时,就可以作为单例的实现方式。

 

下面是引自《Java in a Nutsbell》中必须知道的enum特性,以了解及更有力的使用它们:

1. 枚举没有公共的构造函数,枚举类型唯一的实例就是这些枚举声明。

 

2. 枚举类型不是Cloneable,所以无法为现有的实例创建副本。

 

3. 枚举类型实现了java.io.Serializable,所以它们可以被序列化,但java的序列化机制会特别处理它们,以确保不会有新的实例被创建。

 

4. 枚举类型的实例是永远都不会变的:每一个枚举类型值都会保留它自己的特性。

 

5. 枚举类型的实例是存储于类型本身的public static final字段里,因为这些字段为final,所以它们不可能被不恰当的值改写。

 

6. 依照惯例,枚举类型的值都是使用大写字母来编写,就和其他static final字段一样。

 

7. 因为有一个严格限制的具有不同枚举值的集合,所以使用“==”运算符比较枚举值来代替调用equals() Method 一定是安全的。

 

8. 然而,枚举集合的确有个可行的equals() method。该method在内部使用==而且他被定义为final,所以他无法被覆盖。这个可行的equals() method允许枚举值被用作类似Set、List与Map Collection的成员。

 

9. 枚举类型有个可行的hashCode() method,与它们的equals() method一致。和equals()一样,hashCode()也被定义为final的。它允许枚举值配合类似java.util.HashMap这样的类一起使用。

 

10. 枚举类型实现了Java.lang.comparable,而且compareTo() method会依它们出现在enum声明里的顺序来排序枚举值。

 

11. 枚举类型包括了可行的toString() method,他会返回枚举值的名称。例如,WeekDay.SUN.toString()在默认情况下会返回“SUN”字符串,此method并没有被定义为final,enum类型可以依选择提供custom implementation。

 

12. 枚举类型提供了一个静态valueOf(),它与默认的toString()相反。把一个字符串变成一个枚举对象:static valueOf() Method。

 

13. ordinal():获得这个枚举类的index(从0开始的)。

 

14. 静态的values() method,返回一个包含完整元素的数组。

 

15. 枚举类型是java.lang.Enum的子类,他是在java5.0出现的(Enum 本身并不是枚举类型)。你不能以手动方式扩展Enum类以产生枚举类型,如果试图这样做,那么会产生变异错误。定义枚举类型的唯一方式就是使用enum关键字。

 

16. 要扩展枚举类型是不可能的。枚举类型实际上是final,但final关键字在它们的声明里是不必要且不被允许的!因为enum实际上是final,所以它不会是abstract。

 

17. 和类一样,枚举类型可以实现接口。

 

 

在5.0以后,switch语句除了支持byte、short、int和char外,还支持enum(枚举)。

如果switch表达式被判定为null,会抛出空指针异常(NullPointException)。使用null作为case的值是不合法的!可以try!而且在switch中使用枚举,一般要将default:子句包含进来,不然编译器会产生-Xlint警告信息,好让你知道你没有编写程序代码来处理枚举类型所有的可能值,即使你的每一个枚举都写了一个case时,也要将defaul:子句加进来,这可以处理在你的switch语句编译完成之后,有新的值被加入枚举类型的情况。

所以,在switch中使用枚举时,都要记得加default:子句。