枚举是JDK1.5引入的新特性。被enum关键字修饰的类就是一个枚举类。
创新互联建站服务项目包括泽州网站建设、泽州网站制作、泽州网页制作以及泽州网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,泽州网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到泽州省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!
关于枚举,阿里巴巴开发手册有这样两条建议:
枚举类名带上 Enum 后缀,枚举成员名称需要全大写,单词间用下划线隔开。
如果变量值仅在一个固定范围内变化用 enum 类型来定义。
一 枚举类有哪些特点
创建一个ColorEnum的枚举类,通过编译,再反编译看看它发生了哪些变化。
- public enum ColorEnum {
- RED,GREEN,BULE;
- }
使用命令javac ColorEnum.java进行编译生成class文件,然后再用命令javap -p ColorEnum.class进行反编译。
去掉包名,反编译后的内容如下:
- public final class ColorEnum extends Enum{
- public static final ColorEnum GREEN;
- public static final ColorEnum BULE;
- private static final ColorEnum[] $VALUES;
- public static ColorEnum[] values();
- public static ColorEnum valueOf(java.lang.String);
- private ColorEnum();
- static {};
- }
二 枚举创建线程安全的单例模式
- public enum SingletonEnum {
- INSTANCE;
- public void doSomething(){
- // dosomething...
- }
- }
这样一个单例模式就创建好了,通过SingletonEnum.INSTANCE来获取对象就可以了。
2.1 序列化造成单例模式不安全
一个类如果如果实现了序列化接口,则可能破坏单例。每次反序列化一个序列化的一个实例对象都会创建一个新的实例。
枚举序列化是由JVM保证的,每一个枚举类型和定义的枚举变量在JVM中都是唯一的,在枚举类型的序列化和反序列化上,Java做了特殊的规定:在序列化时Java仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过java.lang.Enum的valueOf方法来根据名字查找枚举对象。同时,编译器是不允许任何对这种序列化机制的定制的并禁用了writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法,从而保证了枚举实例的唯一性。
2.2 反射造成单例模式不安全
通过反射强行调用私有构造器来生成实例对象,造成单例模式不安全。
- Class> aClass = Class.forName("xx.xx.xx");
- Constructor> constructor = aClass.getDeclaredConstructor(String.class);
- SingletonEnum singleton = (SingletonEnum) constructor.newInstance("Java旅途");
但是使用枚举创建的单例完全不用考虑这个问题,来看看newInstance的源码!
- public T newInstance(Object ... initargs)
- throws InstantiationException, IllegalAccessException,
- IllegalArgumentException, InvocationTargetException
- {
- if (!override) {
- if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
- Class> caller = Reflection.getCallerClass();
- checkAccess(caller, clazz, null, modifiers);
- }
- }
- // 如果是枚举类型,直接抛出异常,不让创建实例对象!
- if ((clazz.getModifiers() & Modifier.ENUM) != 0)
- throw new IllegalArgumentException("Cannot reflectively create enum objects");
- ConstructorAccessor ca = constructorAccessor; // read volatile
- if (ca == null) {
- ca = acquireConstructorAccessor();
- }
- @SuppressWarnings("unchecked")
- T inst = (T) ca.newInstance(initargs);
- return inst;
- }
如果是enum类型,则直接抛出异常Cannot reflectively create enum objects,无法通过反射创建实例对象!
三 通过枚举消除if/else
假如要写一套加密接口,分别给小程序、app和web端来使用,但是这三种客户端的加密方式不一样。一般情况下我们会传一个类型type来判断来源,然后调用对应的解密方法即可。代码如下:
- if("WEIXIN".equals(type)){
- // dosomething
- }else if("APP".equals(type)){
- // dosomething
- }else if("WEB".equals(type)){
- // dosomething
- }
现在使用枚举来消除这些if/else。
写一个加密用的接口,有加密和解密两个方法。然后用不同的算法去实现这个接口完成加解密。
- public interface Util {
- // 解密
- String decrypt();
- // 加密
- String encrypt();
- }
创建一个枚举类来实现这个接口
- public enum UtilEnum implements Util {
- WEIXIN {
- @Override
- public String decrypt() {
- return "微信解密";
- }
- @Override
- public String encrypt() {
- return "微信加密";
- }
- },
- APP {
- @Override
- public String decrypt() {
- return "app解密";
- }
- @Override
- public String encrypt() {
- return "app加密";
- }
- },
- WEB {
- @Override
- public String decrypt() {
- return "web解密";
- }
- @Override
- public String encrypt() {
- return "web加密";
- }
- };
- }
最后,获取到type后,直接调用解密方法就行了。
- String decryptMessage = UtilEnum.valueOf(type).decrypt();
以后,如果新增了一个其他加密方式,只需要修改上面的枚举类就完成了,业务代码都不需要改动。
这就是枚举类比较高级的两个用法。
本文转载自微信公众号「Java旅途」,可以通过以下二维码关注。转载本文请联系Java旅途公众号。
网页标题:Coder,我怀疑你并不会枚举
文章转载:http://www.shufengxianlan.com/qtweb/news44/154044.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联