天天看点

详解Java中的枚举枚举

枚举

在很多的编程语言中,枚举是一种比较常见的原生类型,枚举是一种比较常见的原生类型,但是在Java里面,一直到 JDK 1.5 之后才正式引入了枚举结构,其主要的目的是进行多例设计模式的替换。

提示:实际上,传统的多例设计模式是在进行Java开发的过程中,不得已而使用的一种设计结构,因为需要控制对象产生个数,而传统的多例设计模式需要通过一个具体的static方法来获取指定类型的实例化对象,可是在获得的时候必须传入一些标记,于是很多习惯于使用枚举结构的开发人员来说就表示严重的不习惯。

但是对于一直从事Java开发的工程人员来说,由于可能一直没有使用枚举的习惯,所以反而觉得多例设计设计模式简单明了。

一、定义枚举类

在 JDK 1.5 之后,如果需要定义枚举类,那么可以直接使用enum关键字来完成,而枚举类定义的时候需要提供好若干个实例化对象。

范例:定义枚举类

enum Color{ //定义枚举类
	RED,GREEN,BLUE; //描述枚举对象
}
public class Test {
	public static void main(String[] args) {
		Color c = Color.RED; //直接获取指定对象
		System.out.println(c);
	}
}

/**
	程序执行结果:RED
**/
           

此时的Color类就相当于是一个多例设计,但是与传统的多例设计相比,此时的Color类可以直接获取类中指定的实例化对象,并且避免了之前需要传递参数getInstance()方式来获取。

范例:使用中文定义枚举对象

enum Color{ //定义枚举类
	红色,绿色,蓝色; //描述枚举对象
}
public class Test {
	public static void main(String[] args) {
		Color c = Color.红色; //直接获取指定对象
		System.out.println(c);
	}
}

/**
	程序执行结果:红色
**/
           

在Java中可以直接使用中文的形式来进行变量或者对象的声明,所以此时使用中文完全没有问题,在枚举对象输出的时候也会自动调用toString()方法,而它所返回的默认内容就是枚举对象的名称。

在使用传统多例设计设计模式进行开发的过程之中,很难全面的知道到底有多少个对象可以供用户使用,但是如果直接使用枚举这些信息都可以非常直白地描述出来。

范例:获取枚举中的全部数据信息

enum Color{ //定义枚举类
	RED,GREEN,BLUE; //描述枚举对象
}
public class Test {
	public static void main(String[] args) {
		for(Color c : Color.values()) {//values()可以获取全部枚举信息
			System.out.print(c + "、");
		}
	}
}

/**
	程序执行结果:RED、GREEN、BLUE、
**/
           

本程序直接通过枚举中提供的values()方法将所有的枚举对象转为数组的形式返回,随后利用for-each输出枚举中的每一项信息定义,在 JDK 1.5 之后,不仅追加了枚举的结构,同时也针对于枚举改进了switch结构。

swich进化史:
  • JDK 1.0 ~ JDK 1.4 :switch支持整型、字符型判断;
  • JDK 1.5:switch支持枚举判断;
  • JDK 1.7:switch支持String的判断;
  • JDK 1.13:switch可以结合yield实现局部返回。

范例:在switch中使用枚举进行判断

enum Color{ //定义枚举类
	RED,GREEN,BLUE; //描述枚举对象,此处的大写与多例设计中的大写意义相同
}
public class Test {
	public static void main(String[] args) {
		Color c =Color.RED; //获取枚举对象
		switch(c) {
			case RED:
				System.out.println("【RED】红色");
				break;
			case GREEN:
				System.out.println("【GREEN】绿色");
				break;
			case BLUE:
				System.out.println("【BLUE】蓝色");
				break;
		}
	}
}

/**
	程序执行结果:【RED】红色
**/
           

这种switch判断仅仅在枚举上,如果是多例设计模式,那么没有这样的支持语句,只能够通过各种if以及对象比较的方法来完成。

二、Enum类

在Java里面需要通过enum关键字来实现枚举类的定义,但是严格意义上来讲,使用enum关键字所定义的本质上相当于一个类继承了Enum父类结构,即:如果想要研究枚举,那么最佳的做法就是去观察一下Enum类的定义:

public abstract class Enum<E extends Enum<E>>//此泛型是由枚举来控制的
extends Object
implements Constable, Comparable<E>, Serializable
           

首先可以发现,Enum类属于一个抽象类,按照Java面向对象的设计结构来讲,所有的抽象类一定要提供有相应的子类,如果子类不属于抽象类,则一定要覆写父类中的全部抽象方法,但是Enum类中并没有提供抽象方法,而之所以将其定义为抽象类是因为不希望这个类直接被使用,而在Enum类中提供有如下的几个方法:

详解Java中的枚举枚举

通过定义可以发现,在枚举的构造方法上使用了protected访问控制权限,那么就证明了此时的枚举中的构造方法使用了封装定义(不管是单例设计模式还是多例设计模式,首要的要求就是构造方法私有化)。

范例:观察Enum类中的使用

enum Color{ //定义枚举类
	RED,GREEN,BLUE; //描述枚举对象,此处的大写与多例设计中的大写意义相同
}
public class Test {
	public static void main(String[] args) {
		for(Color c : Color.values() ) {
			System.out.println("【"+ c +"】名称 = " + c.name() + "、序号 = " + c.ordinal());
		}	
	}
}

/**
	程序执行结果:【RED】名称 = RED、序号 = 0
				【GREEN】名称 = GREEN、序号 = 1
				【BLUE】名称 = BLUE、序号 = 2
**/
           

通过以上的程序代码就可以清楚地发现,enum定义的枚举结构就相当于一个类继承了Enum父类的结构。

总结:请解释enum和Enum的区别?

  • enum是在JDK 1.5 之后提供枚举定义的关键字;
  • 使用enum关键字定义的枚举类从本质上就相当于定义了一个继承Enum父类的结构。

三、扩展枚举结构

虽然Java是在 JDK 1.5 之后才正式提供了枚举类型,但是从其应用的角度来讲,其枚举的功能已经要比任何语言中所要提供的枚举功能都要强大,因为传统的枚举仅仅是能够定义若干个枚举项(对象),而在Java中可以将类的结构充分的定义在枚举中。

1、在枚举中定义属性与方法

enum Color{ //定义枚举类
	//此时类中不提供有无参的构造方法,所以每一个枚举项(实例化对象)都必须明确的调用有参构造方法并传递参数
	RED("红色"),GREEN("绿色"),BLUE("蓝色"); //枚举项必须写在类的首行
	private String content; //定义属性
	Color(String content){ //此时的枚举类中不提供无参构造
		this.content = content;
	}
	public String toString() { //覆写toString()方法
		return this.content;
	}	
}
public class Test {
	public static void main(String[] args) {
		for(Color c : Color.values() ) {
			System.out.println("【"+ c +"】名称 = " + c.name() + "、序号 = " + c.ordinal());
		}	
	}
}

/**
	程序执行结果:【红色】名称 = RED、序号 = 0
				【绿色】名称 = GREEN、序号 = 1
				【蓝色】名称 = BLUE、序号 = 2
**/
           

枚举的本质就是多例设计模式,而多例设计模式里面的首要的实现要求:类中的构造方法私有化,当在枚举中定义构造方法的时候绝对不要使用public访问权限,否则会出现有如下的编译错误。

范例:错误的构造方法定义

enum Color{ //定义枚举类
	//此时类中不提供有无参的构造方法,所以每一个枚举项(实例化对象)都必须明确的调用有参构造方法并传递参数
	RED("红色"),GREEN("绿色"),BLUE("蓝色"); //枚举项必须写在类的首行
	private String content; //定义属性
	public Color(String content){ //此时的枚举类中不提供无参构造
		this.content = content;
	}
	public String toString() { //覆写toString()方法
		return this.content;
	}	
}
public class Test {
	public static void main(String[] args) {
		for(Color c : Color.values() ) {
			System.out.println("【"+ c +"】名称 = " + c.name() + "、序号 = " + c.ordinal());
		}	
	}
}

/**
	程序编译结果:Illegal modifier for the enum constructor; 					only private is permitted.
**/
           

2、枚举整体运行结构实际上是和类是相同的,那么既然和类是相同的,所以枚举本身也可以实现接口,而对于接口的抽象方法,可以分开实现,也可以集中实现。

范例:公共实现接口的抽象方法

interface IMessage{//定义一个获取消息的接口
	public String getColor();//抽象方法
}
enum Color implements IMessage{ //定义枚举类
	//此时类中不提供有无参的构造方法,所以每一个枚举项(实例化对象)都必须明确的调用有参构造方法并传递参数
	RED("红色"),GREEN("绿色"),BLUE("蓝色"); //枚举项必须写在类的首行
	private String content; //定义属性
	Color(String content){ //此时的枚举类中不提供无参构造
		this.content = content;
	}
	public String getColor() { //公共覆写方法
		return this.content;
	}	
}
public class Test {
	public static void main(String[] args) {
		IMessage msg = Color.RED; //获取一个接口的子类对象
		System.out.println(msg.getColor());
	}
}

/**
	程序执行结果:红色
**/
           

除了以上的方式之外,在枚举中的每一个枚举对象也可以分开来实现具体的抽象方法。

范例:每一个枚举项实现抽象方法

interface IMessage{//定义一个获取消息的接口
	public String getColor();//抽象方法
}
enum Color implements IMessage{ //定义枚举类
	//此时类中不提供有无参的构造方法,所以每一个枚举项(实例化对象)都必须明确的调用有参构造方法并传递参数
	RED{
		public String getColor() {
			return "红色";
		}
	},GREEN{
		public String getColor() {
			return "绿色";
		}
	},BLUE{
		public String getColor() {
			return "蓝色";
		}
	}; 
	
}
public class Test {
	public static void main(String[] args) {
		IMessage msg = Color.RED; //获取一个接口的子类对象
		System.out.println(msg.getColor());
	}
}

/**
	程序执行结果:红色
**/
           

3、在枚举中也可以直接定义抽象方法,而对于这些抽象方法就要求每一个枚举项都必须明确的进行覆写。

enum Color{ //定义枚举类
	//此时类中不提供有无参的构造方法,所以每一个枚举项(实例化对象)都必须明确的调用有参构造方法并传递参数
	RED{
		public String getColor() {
			return "红色";
		}
	},GREEN{
		public String getColor() {
			return "绿色";
		}
	},BLUE{
		public String getColor() {
			return "蓝色";
		}
	}; 
	public abstract String getColor();//抽象方法
	
}
public class Test {
	public static void main(String[] args) {
		System.out.println(Color.BLUE.getColor());
	}
}

/**
	程序执行结果:蓝色
**/
           

实际上通过以上的几个程序的功能就可以非常清楚地发现,原来整个的枚举从它的定义来说,是所有语言设计之最。

四、枚举应用案例

经过一系列的分析之后我们已经清楚了枚举的基本使用,但是随后还需要进一步的去思考,枚举在我们的实际开发过程之中应该如何去使用呢?首先一定要清楚使用枚举就相当于定义了一个操作的范畴,那么既然有了操作的范畴,对于一些类的对象就有了使用的固定环境,例如:如果要定义图书类,图书肯定会有分类,而这个分类就可以通过枚举来描述。

范例:使用枚举定义图书的范围

enum BookType{ //定义枚举类
	MATH("数学"),PROGRAM("软件编程"),GAME("游戏");
	private String content;
	private BookType(String content) {
		this.content = content;
	}
	public String toString() {
		return this.content;
	}
}
class Book{
	private String title;
	private String author;
	private double price;
	private BookType type;
	public Book() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Book(String title, String author, double price, BookType type) {
		super();
		this.title = title;
		this.author = author;
		this.price = price;
		this.type = type;
	}
	/**
	 * @return the title
	 */
	public String getTitle() {
		return title;
	}
	/**
	 * @param title the title to set
	 */
	public void setTitle(String title) {
		this.title = title;
	}
	/**
	 * @return the author
	 */
	public String getAuthor() {
		return author;
	}
	/**
	 * @param author the author to set
	 */
	public void setAuthor(String author) {
		this.author = author;
	}
	/**
	 * @return the price
	 */
	public double getPrice() {
		return price;
	}
	/**
	 * @param price the price to set
	 */
	public void setPrice(double price) {
		this.price = price;
	}
	/**
	 * @return the type
	 */
	public BookType getType() {
		return type;
	}
	/**
	 * @param type the type to set
	 */
	public void setType(BookType type) {
		this.type = type;
	}
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "【图书】名称:" + this.title + "、作者:" + this.author + "、价格:" + this.price + "、类型:" + this.type ;
	}
}
public class Test {
	public static void main(String[] args) {
		System.out.println(new Book("高等数学" , "小贾老师" , 99.8 , BookType.MATH));
	}
}

/**
	程序执行结果:【图书】名称:高等数学、作者:小贾老师、价格:99.8、类型:数学
**/
           

很多同学也会觉得,即使此时不使用枚举也可以实现,但是毕竟从枚举产生到现在已经度过了15年的时间了,现在对于枚举的使用早已经深入人心了。