Java枚举:小小enum,优雅而干净

《Java编程思想》中有这么一句话:“有时偏偏由于它,你才可以‘优雅而干净’地解决问题”——这句话说的是谁呢?就是本篇的主角——枚举(Enum)——你们鼓掌了。html

在以前很长时间一段时间里,都不怎么用枚举,由于总感受它没什么用处——这其实就是“自我认知”的短见。当一我的一直蹲在本身的深井里而不敢跳出来的话,那他真的只能看到井口那么大点的天空java

随着时间的推移,我作的项目愈来愈多,和枚举见面的机会也愈来愈多,因而我就渐渐地对它愈来愈有兴趣,研究得多了,才发现原来枚举如此的优秀。sql

1)枚举的常规用法

一个精简的枚举很是的干净优雅,见下例。数据库

public enum Chenmo {
	WANGER, WANGSAN, WANGSI
}
复制代码

咱们为沉默枚举建立了三个值,分别是王2、王3、王四。这段代码实际上调用了3次Enum(String name, int ordinal)(ordinal单词的意思为顺序),也就是:编程

new Enum<Chenmo>("WANGER", 0);
new Enum<Chenmo>("WANGSAN", 1);
new Enum<Chenmo>("WANGSI", 2);
复制代码

咱们来遍历输出一下枚举:安全

for (Chenmo e : Chenmo.values()) {
    System.out.println(e);
}
//输出
//WANGER
//WANGSAN
//WANGSI
复制代码

2)做为switch的判断条件

使用枚举做为switch语句判断条件能让咱们的代码可读性更强,示例以下。微信

Chenmo key = Chenmo.WANGER;
switch (key) {
case WANGSI:
	System.out.println("今天我送出一个CSDN大鼠标垫");
	break;
case WANGSAN:
	System.out.println("今天我被坑一个CSDN学院年卡");
	break;
default:
	System.out.println("今天我一边高兴,一边失落");
	break;
}
复制代码

在经过case关键字判断的时候,能够直接使用枚举值,很是简洁。另外,在编译期间限定类型,能够有效的避免越界的状况——字符串常量类型在做为switch判断条件的时候很容易由于误写而发生越界问题。ide

3)枚举实现单例

《Effective Java》一书中对使用枚举实现单例的方式推崇备至:this

使用枚举实现单例的方法虽然尚未普遍采用,可是单元素的枚举类型已经成为实现Singleton的最佳方法。spa

我以为“虽然尚未普遍采用”几个字能够去掉了,时至今日,你们应该都知道:使用枚举实现单例是一种很是好的方式。

先来看“双重校验锁”实现的单例:

public class SingleTon2 {

	 // 私有化构造方法
	private SingleTon2() {
	};

	private static volatile SingleTon2 singleTon = null;

	public static SingleTon2 getInstance() {

		// 第一次校验
		if (singleTon == null) {
			synchronized (SingleTon2.class) {
				// 第二次校验
				if (singleTon == null) {
					singleTon = new SingleTon2();
				}
			}
		}
		return singleTon;
	}
}
复制代码

再来看枚举实现的单例:

public enum SingleTon {

	 INSTANCE;
	
	public void method() {
		System.out.println("我很快乐!");
	}
}
复制代码

不比不知道,一比吓一跳啊!枚举方式的单例简单到爆——为了避免至于看起来太过精简,我还加了一个输出“我很快乐”的方法。

枚举实现的单例可轻松地解决两个问题:

①、线程安全问题。由于Java虚拟机在加载枚举类的时候,会使用ClassLoader的loadClass方法,这个方法使用了同步代码块来保证线程安全。

②、避免反序列化破坏单例。由于枚举的反序列化并不经过反射实现。

4)枚举可与数据库交互

咱们能够配合Mybatis将数据库字段转换为枚举类型。如今假设有一个数据库字段check_type的类型以下:

`check_type` int(1) DEFAULT NULL COMMENT '检查类型(1:未经过、2:经过)',
复制代码

它对应的枚举类型为CheckType,代码以下:

public enum CheckType {
	NO_PASS(0, "未经过"), PASS(1, "经过");
	private int key;

	private String text;

	private CheckType(int key, String text) {
		this.key = key;
		this.text = text;
	}

	public int getKey() {
		return key;
	}

	public String getText() {
		return text;
	}

	private static HashMap<Integer,CheckType> map = new HashMap<Integer,CheckType>();
	static {
		for(CheckType d : CheckType.values()){
			map.put(d.key, d);
		}
	}
	
	public static CheckType parse(Integer index) {
		if(map.containsKey(index)){
			return map.get(index);
		}
		return null;
	}
}
复制代码

CheckType枚举类比咱们刚开始见到的那个Chenmo枚举类要复杂一些。

第一,CheckType新添加了构造方法,还有两个字段,key为int型,text为String型。

第二,CheckType中有一个public static CheckType parse(Integer index)方法,可将一个Integer经过key的匹配转化为枚举类型。

那么如今,咱们能够在Mybatis的配置文件中使用typeHandler将数据库字段转化为枚举类型。

<resultMap id="CheckLog" type="com.entity.CheckLog">
  <id property="id" column="id"/>
  <result property="checkType" column="check_type" typeHandler="com.CheckTypeHandler"></result>
</resultMap>
复制代码

其中checkType字段对应的类以下:

public class CheckLog implements Serializable {

    private String id;
    private CheckType checkType;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public CheckType getCheckType() {
        return checkType;
    }

    public void setCheckType(CheckType checkType) {
        this.checkType = checkType;
    }
}
复制代码

CheckTypeHandler转换器的类源码以下:

public class CheckTypeHandler extends BaseTypeHandler<CheckType> {

	@Override
	public CheckType getNullableResult(ResultSet rs, String index) throws SQLException {
		return CheckType.parse(rs.getInt(index));
	}

	@Override
	public CheckType getNullableResult(ResultSet rs, int index) throws SQLException {
		return CheckType.parse(rs.getInt(index));
	}

	@Override
	public CheckType getNullableResult(CallableStatement cs, int index) throws SQLException {
		return CheckType.parse(cs.getInt(index));
	}

	@Override
	public void setNonNullParameter(PreparedStatement ps, int index, CheckType val, JdbcType arg3) throws SQLException {
		ps.setInt(index, val.getKey());
	}
}
复制代码

CheckTypeHandler 的核心功能就是调用CheckType枚举类的parse()方法对数据库字段进行转换。

5)枚举会比静态常量更消耗内存吗?

说完枚举最经常使用的4个知识点后,咱们来讨论一下“枚举会比静态常量更消耗内存吗?”这个话题——知乎上有人问这样的问题,还有不少人参与回答。

按个人理解,问这个问题的人就好像是在问“0.000,001”比“0.000,000,99”大吗?你说是吗?


上一篇:若是有人再问你 Java 的反射,把这篇文章扔给他

下一篇:Java注解(Annotation):请不要小看我!

微信搜索「沉默王二」公众号,关注后回复「免费视频」获取 500G 高质量教学视频(已分门别类)。

相关文章
相关标签/搜索