枚举
没想到一个小小的枚举,也有这么深的知识。
为了获取枚举上一个废弃标识注解,找遍了百科,坑死我了。
还好公司有大佬,破了难题。很奇怪他是怎么知道用getField的。
--一路追踪,原来一开始想的都是内部类,怎么得到实例对象,一开始就偏了。 终于明白了。故记下本次学习历程。再次明白了关键字搜索的重要性。
1、枚举基本介绍
参考博文:--https://www.iteye.com/blog/whitesock-728934
https://wenku.baidu.com/view/5ddd914fb307e87100f69603.html
https://www.cnblogs.com/draem0507/p/4110987.html
1) Enum声明了name()方法和oridinal()方法,分别用于返回枚举值的名称和该枚举值在枚举类型中声明的顺序(从0开始)。
2)单例的实现
序列化过程中写入流的只有name;反序列化过程中通过调用Enum.valueOf(Class<T> enumType, String name)静态方法构造枚举值,从而保证了枚举值的单例性。
3)ENUM$VALUES:是个private static final的数组。在枚举类初始化的时候,会实例化所有的枚举对象然后按顺序放在这个数组中
2、枚举的反射
参考博文:-https://blog.csdn.net/lufeng20/article/details/8835135
1)反射获取枚举上注解
先反射获取枚举实例如accountEnum所在class,然后获取枚举class上声明的该枚举field字段,然后用字段获取其上的Annotation注解,这样在调用注解的相关方法即可
(遇到问题可google英文)
示例:boolean deprecated=AccountRankEnum .class.getField("UNOPEN").isAnnotationPresent(Deprecate.class);//==true
注意:getField()--只能根据枚举的name()来获取对应的枚举实例对象。综合上述基本介绍,枚举的序列化写入流的只有 name(),所以根据code或message是无法反射到对象的。
public enum AccountRankEnum implements Messageable{
/** 未激活 */
@Deprecated
UNOPEN("W", "无"),
/** 快速注册用户 */
TWO("TWO", "二级"),
/** 正常用户 */
THREE("THREE", "三级"),
FACESIGN("FACESIGN","面签");
/** 枚举值 */
private final String code;
/** 枚举描述 */
private final String message;
/**
* 构造一个<code>UserStatusEnum</code>枚举对象
*
* @param code
* @param message
*/
private AccountRankEnum(String code, String message) {
this.code = code;
this.message = message;
}
..........
}
2)为什么用getField?
getField:主要用于反射获取类上属性字段。
对枚举类enum来说,枚举底层就是继承了Enum这个类 ,通过反编译.class文件我们可以发现,其实是在static静态代码块中完成了属性的初始化,枚举值其实都是static的静态成员,并加了final修饰词。所以可以用getField进行获取某个枚举值对象。.
反编译对象-字节码代码如下:javap -c -encodeing UTF-8 AccountRankEnum.class
字节码查看-参考博文:https://blog.csdn.net/kwame211/article/details/77677662/
3、枚举类的动态代理
1) 不能进行cglib动态代理:原因如2),cglib是利用Enhancer获取代理对象的子类,然而枚举并没有办法被继承 ,因为枚举类时final修饰的,不能进行实例化和继承。(Cglib代理无法代理final修饰的)
报错如下:java.lang.IllegalArgumentException: Cannot subclass final class com.xx.AccountRankEnum
Cglib代码如下
MyMethodIntercepter ,实现MethodInterceptor,
//getTrueTarget传入是接口的实现类或具体的某个类。
AccountRankEnum accountEnum=(AccountRankEnum)new MyMethodIntercepter().getTrueTarget(AccountRankEnum.UNOPEN.getClass());
System.out.println(accountEnum);
System.out.println(accountEnum.code());
----------------------------------
public class MyMethodIntercepter implements MethodInterceptor {
Object trueTarget;
public Object getTrueTarget(Class trueTarget) {
this.trueTarget = trueTarget;
return Enhancer.create(trueTarget,this);
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("In cglib before invoke");
Object result=proxy.invoke(obj,args);
System.out.println("In cglib after invoke");
return result;
}
}
2)若实现了接口,可以进行jdk代理:
若没有实现接口,会报错: java.lang.IllegalArgumentException: class com.xx.AccountRankEnumis not an interface
jdk代理代码:( jdk代理只能代理接口)
MyInvocationHandler 实现InvocationHandler,进行代理,代码如下:class MyInvocationHandler
测试代码:
Messageable accountEnum=(Messageable)new MyInvocationHandler().getProxyTarget(AccountRankEnum.UNOPEN);
System.out.println(accountEnum);
System.out.println(accountEnum.code());
public class MyInvocationHandler implements InvocationHandler {
Object trueTarget;
public Object getProxyTarget(Object obj){
this.trueTarget=obj;
return Proxy.newProxyInstance(Messageable.class.getClassLoader(),new Class[]{Messageable.class},this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before:"+method.getName());
Object result=method.invoke(trueTarget);
System.out.println("after:"+result);
return result;
}
}
来源:CSDN
作者:Annie_ya
链接:https://blog.csdn.net/Annie_ya/article/details/103879572