【Java】枚举类型和底层分析,枚举的单例模式

一. 枚举(enumeration)的引入和模拟

需求: 定义一个Employee(员工),使用一个变量restday来表示他哪一天休息(一周的哪一天)。

class Employee{

	private int restday;

	public void setRestday(int restday)
	{
		this.restday = restday;
	}
	public int getRestday()
	{	
		return restday;
	}
}

class EnumerationDemo
{
	public static void main(String[] args) 
	{
		Employee employee = new Employee();
		employee.setRestday(13);
	}	
}

上述使用int类型来表示星期几存在的问题:
(1):类型不安全,完全可以设置非[1,7]之间的数。
(2):业务含义不够明确,设置1表示周几?周一/周日?

解决方案:专门使用一个类Weekday来表示周一到周日,使用7个常量来表示。

class Weekday
{
	// Monday、Tuesday、Wednesday、Thursday、Friday、Saturday、Sunday 
	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;
}

此时,业务含义很明确,因为Weekday.WEDNESDAY就表示周三的意思。
但是, 因为在Employee中的restday的类型是int类型,我们依然可以随意设置int类型的数据。所以,还是没有解决数据类型不安全的问题。

因为int类型不安全,我们把休息日使用一个对象类型来表示,并固定该休息日的值只能是周一到周日。

class Weekday
{
	// Monday、Tuesday、Wednesday、Thursday、Friday、Saturday、Sunday 
	private Weekday(){}; // 私有化构造器
	public static final Weekday Monday = new Weekday();
	public static final Weekday Tuesday = new Weekday();
	public static final Weekday Wednesday = new Weekday();
	public static final Weekday Thursday = new Weekday();
	public static final Weekday Friday = new Weekday();
	public static final Weekday Saturday = new Weekday();
	public static final Weekday Sunday = new Weekday();
}

class Employee{

	private Weekday restday;

	public void setRestday(Weekday restday)
	{
		this.restday = restday;
	}
	public Weekday getRestday()
	{	
		return restday;
	}
}

class EnumerationDemo
{
	public static void main(String[] args) 
	{
		Employee employee = new Employee();
		employee.setRestday(Weekday.Saturday);
		Weekday restday = employee.getRestday();
		
		if (restday == Weekday.Saturday || restday == Weekday.Sunday)
		{
			System.out.println("不上班,休息!");
			return;
		}
		System.out.println("工作....");
	}	
}

二. 枚举的定义

枚举是从java5开始提供的一种新的数据类型,是一个特殊的类,就是固定的多个常量对象的集合。简单来说,枚举就是一个特殊的类。

枚举主要用来表示事物固定的类型。(后面慢慢学)

定义格式:

enmu 类名
{ 
	常量A, 常量B, 常量C;
} 

如:

enum Weekday
{
	 Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday;
}

反编译:
在这里插入图片描述

在这里插入图片描述

等价于:

class Weekday
{
	// Monday、Tuesday、Wednesday、Thursday、Friday、Saturday、Sunday 
	private Weekday(){}; // 私有化构造器
	public static final Weekday MONDAY = new Weekday();
	public static final Weekday TUESDAY = new Weekday();
	public static final Weekday WEDNESDAY = new Weekday();
	public static final Weekday THURSDAY = new Weekday();
	public static final Weekday FRIDAY = new Weekday();
	public static final Weekday SATURDAY = new Weekday();
	public static final Weekday SUNDAY = new Weekday();
}

三. 枚举的特点

【这样写没有任何意义,每一个特点都是通过具体的原因引入的,不是在这里写总结】

(1) 枚举的直接父类,java.lang.enum,但是不能显示集成enum;

(2) 枚举就相当于一个类,可以定义构造方法、成员变量、普通方法、抽象方法等。

(3) 默认私有构造方法,即使不写访问权限也是private(是一个假的构造器,底层没有无参构造器

(4) 每个实例分别用一个全局常量表示,枚举类的对象是固定的,实例个数有限(不能再增加),不能使用new关键字。

(5) 枚举实例必须位于枚举类型中的第一行,枚举实例表最后要有分号与其他成员分割。

(6) 枚举实例后有花括号时,该实例是枚举类型的匿名内部类对象(查看编译后的class文件)

四. 枚举的使用

(1)枚举中都是全局公共的静态常量,可以直接使用枚举名调用。

	Weekday day = Weekday.SATURDAY;

(2)因为java.lang.Enum类是所有枚举类的父类,所以所有的枚举对象可以调用Enum类中的方法。

	String name = 枚举对象.name();    //返回枚举对象的常量名称.
	int ordinal = 枚举对象.ordinal(); //返回枚举对象的序号,从0开始.
	String str = 枚举对象.toString(); //返回枚举对象的常量名称

如:

	System.out.println(Weekday.FRIDAY .name());
	System.out.println(Weekday.FRIDAY .ordinal());
	System.out.println(Weekday.FRIDAY .toString());
---------- 运行java ----------
Friday
4
Friday

输出完成 (耗时 0) - 正常终止

(3)编译器生成的枚举类的静态方法:枚举类型[] values();

	Weekday[] values  = Weekday.values();//返回当前枚举类型所有的常量,用一个数组封装起来
	for(Weekday w : values){
			System.out.println(w);
	}		
---------- 运行java ----------
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday

输出完成 (耗时 0) - 正常终止

枚举类型 valueOf(String name);

Weekday day = Weekday.valueOf("MONDAY");//把一个指定名称字符串转换为当前枚举类中同名的常量

这个使用场景:一般前端传递数据到后端时,经常使用String类型,可以通过valueOf将String类型的数量转为枚举类型。

(4)从jave5开始出现枚举,switch也支持操作枚举类型。

switch只支持int类型,支持枚举是因为底层使用的枚举对象的ordinal;
而ordinal的类型依然是int类型

		switch(Weekday.FRIDAY)
		{
			case MONDAY : break;
			case TUESDAY : break;
			case WEDNESDAY : break;
		}

反编译:
在这里插入图片描述

补充:枚举的单例模式:

在《effective java》书中提到,建议使用枚举类做单例模式,这样很安全,即使使用反射也不能创建对象。

我们先看一下之前写的单例模式:

class ArrayUtil
{
	// (1) 必须在该类中,自己先new一个对象;
	private static final ArrayUtil instance = new ArrayUtil();
	// (2) 私有化构造器;
	private ArrayUtil(){}
	// (3) 向外暴露一个公共的静态方法用于获取自身的对象
	public  static ArrayUtil getInstance(){
		return instance;	
	}	
	// 相关工具方法操作
	public void sort(int[] arr){
		// 排序
	}
}

使用枚举:

// 枚举写法
enum ArrayUtil
{
	INSTANCE;
	// 相关工具方法操作
	public void sort(int[] arr){
		// 排序操作
	}
}

class SingletonDemo 
{
	public static void main(String[] args) 
	{
		System.out.println(ArrayUtil.INSTANCE);// 每次获取到的单例都是相同的
		System.out.println(ArrayUtil.INSTANCE);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值