当前位置: 首页 > 科技观察

Coder,我怀疑你会枚举

时间:2023-03-12 21:12:27 科技观察

枚举是JDK1.5引入的新特性。由enum关键字修饰的类是枚举类。关于枚举,阿里巴巴开发手册有两个建议:枚举类名后缀为Enum,枚举成员名全部大写,单词之间用下划线分隔。如果变量值只在固定范围内变化,则使用枚举类型来定义。1枚举类有什么特点?创建一个ColorEnum枚举类,编译它,然后反编译它,看看它发生了什么变化。publicenumColorEnum{RED,GREEN,BULE;}使用命令javacColorEnum.java编译生成class文件,然后使用命令javap-pColorEnum.class反编译。去掉包名,反编译后的内容如下:被final修饰,所以枚举类不能被继承;枚举类默认继承Enum类,java不支持多重继承,所以枚举类不能继承其他类;枚举类的构造函数是私有的,其他类无法通过构造函数获取对象;枚举类的成员变量是静态修饰的,可以通过类名获取对象。多变的;values()方法是获取所有的枚举实例;valueOf(java.lang.String)根据名称获取对应的实例;第二个枚举创建线程安全的单例模式publicenumSingletonEnum{INSTANCE;publicvoiddoSomething(){//dosomething...}}这样的单例模式是通过SingletonEnum.INSTANCE对象来创建和获取的。2.1序列化使得单例模式不安全如果一个类实现了序列化接口,可能会破坏单例。每次反序列化序列化实例对象时,都会创建一个新实例。枚举序列化由JVM保证。每个枚举类型和定义的枚举变量在JVM中都是唯一的。Java对枚举类型的序列化和反序列化做了特殊的规定:Java在序列化时只输出枚举对象的name属性到结果中,反序列化时使用java.lang.Enum的valueOf方法查找枚举对象根据名称。同时,编译器不允许对这种序列化机制进行任何自定义,禁用了writeObject、readObject、readObjectNoData、writeReplace、readResolve等方法,从而保证了枚举实例的唯一性。2.2反射使得单例模式不安全。实例对象是通过反射强制调用私有构造函数生成的,这使得单例模式不安全。ClassaClass=Class.forName("xx.xx.xx");Constructorconstructor=aClass.getDeclaredConstructor(String.class);SingletonEnumsingleton=(SingletonEnum)constructor.newInstance("JavaJourney");但是使用枚举创建的单例根本不需要考虑这个问题。一起来看看newInstance的源码吧!publicTnewInstance(Object...initargs)throwsInstantiationException,IllegalAccessException,IllegalArgumentException,InvocationTargetException{if(!override){if(!Reflection.quickCheckMemberAccess(clazz,modifiers)){Classcaller=Reflection.getCallerClass();checkAccess(来电者,clazz,null,modifiers);}}//如果是枚举类型,直接抛出异常,不允许创建实例对象!if((clazz.getModifiers()&Modifier.ENUM)!=0)thrownewIllegalArgumentException("Cannotreflectivelycreateenumobjects");ConstructorAccessorca=constructorAccessor;//readvolatileif(ca==null){ca=acquireConstructorAccessor();}@SuppressWarnings("unchecked")Tinst=(T)ca.newInstance(initargs);returninst;}如果是枚举类型,会直接抛出异常无法反射创建枚举对象,无法通过通过反射创建实例对象!3、通过枚举剔除if/else如果你想为小程序、app、web端写一套加密接口,但是这三个客户端的加密方式不同。一般我们会通过A类型类型判断来源,然后调用相应的解密方法。代码如下:if("WEIXIN".equals(type)){//dosomething}elseif("APP".equals(type)){//dosomething}elseif("WEB".equals(type)){//dosomething}现在使用枚举来消除那些if/else。写一个加密的接口,有加密和解密两种方法。然后使用不同的算法实现这个接口来完成加解密。publicinterfaceUtil{//DecryptStringdecrypt();//EncryptStringencrypt();}创建一个枚举类来实现该接口";}},APP{@OverridepublicStringdecrypt(){返回"应用解密";}@OverridepublicStringencrypt(){返回"应用加密";}},WEB{@OverridepublicStringdecrypt(){返回"网页解密";}@OverridepublicStringencrypt(){return"webencryption";}};}最后得到类型后,直接调用解密方法即可。StringdecryptMessage=UtilEnum.valueOf(type).decrypt();以后如果再增加一种加密方式,只需要修改上面的枚举类就可以完成,业务代码不需要改动。这是枚举类的两种更高级的用法。本文转载自微信公众号“Java之旅”,可通过以下二维码关注。转载本文请联系Java之旅公众号。