JAVA中注解是怎么做到的(下)

使用反射操作注解大部分情况下,我们的项目或者开源框架中都定义了大量的注解,而且都是@retention(retentionpolicy.runtime)运行时阶段,我们可以通过反射获取注解中的信息,所以整体遵循下面的一个范式。
自定义注解扫描注解通过反射获取注解的信息,执行相应的逻辑。下面我们重点使用下如何用反射来获取注解的信息。
定义target是注解的注解@inherited@retention( value = retentionpolicy.runtime)@target(value = {elementtype.annotation_type})public @interface annotest { string value() default anno;}定义一个几乎全量信息的注解@annotest(alvinanno)@inherited@retention( value = retentionpolicy.runtime)@target(value = {elementtype.type_use,elementtype.package,elementtype.field, elementtype.type_parameter,elementtype.constructor,elementtype.local_variable})@documentedpublic @interface fullannotest { string value() default fullannotest;}定义测试类和反射代码@fullannotest(package)package com.alvin.java.core.anno;public class parentobj {}@fullannotest(testannoreflect)public class testannoreflect extends @fullannotest(parent)parentobj { @fullannotest(constructor) testannoreflect() { } //注解字段域 private @fullannotest(name) string name; //注解泛型字段域 private @fullannotest(value) t value; //注解通配符 private @fullannotest(list) list list; //注解方法 @fullannotest(method) //注解方法参数 public string hello(@fullannotest(methodparameter) string name) throws @fullannotest(exception) exception { // 注解抛出异常 //注解局部变量,现在运行时暂时无法获取(忽略) @fullannotest(result) string result; result = siting; system.out.println(name); return result; } public static void main(string[] args) throws exception { testannoreflect查看对应的执行结果修饰testannoreflect.class注解value: testannoreflect修饰构造器的注解value: constructor修饰继承父类的注解value: parent修饰注解的注解annotest-value: alvinanno修饰泛型参数t注解value: parameter修饰普通字段域name注解value: name修饰泛型字段t注解value: value修饰泛型注解value: list修饰通配符注解value: generic修饰方法的注解value: method修饰方法抛出错误的注解value: exception修饰方法参数注解value: methodparameter修饰package注解value: packagehello注解的本质和底层实现大家有没有想过注解的本质是什么?
我们先通过反编译查看注解生成的字节码,可以通过javap -v fullannotest.class查看如下:
可以看到,我们的注解是继承自annotation接口。
public interface annotation { boolean equals(object obj); int hashcode(); string tostring(); /** * returns the annotation type of this annotation. * @return the annotation type of this annotation */ class? extends annotation annotationtype();}所以注解相当于一个语法糖一样,可以方便我们使用,本质上它是继承自annotation的一个接口。
那大家有没有想过它的实现类在哪里?比如下面的代码,获取到注解,按照上面的解释,它是一个接口,那调用value()方法时,它具体调用的哪个实现类呢?我们并没有写实现类啊.....
答案当然就是动态代理生成的实现类。
annotest annotest = testtmp.annotationtype().getannotation(annotest.class);system.out.println(修饰注解的注解annotest-value: +annotest.value());我们可以在启动参数添加如下命令可以查看生成的代理类:-dsun.misc.proxygenerator.savegeneratedfiles=true
执行后,生成代理类如下,
代理大致的代码如下:
public final class $proxy2 extends proxy implements fullannotest { private static method m1; private static method m2; private static method m4; private static method m0; private static method m3; public $proxy2(invocationhandler var1) throws { super(var1); } public final boolean equals(object var1) throws { try { return (boolean)super.h.invoke(this, m1, new object[]{var1}); } catch (runtimeexception | error var3) { throw var3; } catch (throwable var4) { throw new undeclaredthrowableexception(var4); } } public final class annotationtype() throws { try { return (class)super.h.invoke(this, m4, (object[])null); } catch (runtimeexception | error var2) { throw var2; } catch (throwable var3) { throw new undeclaredthrowableexception(var3); } } public final string value() throws { try { return (string)super.h.invoke(this, m3, (object[])null); } catch (runtimeexception | error var2) { throw var2; } catch (throwable var3) { throw new undeclaredthrowableexception(var3); } } static { try { m1 = class.forname(java.lang.object).getmethod(equals, class.forname(java.lang.object)); m2 = class.forname(java.lang.object).getmethod(tostring); m4 = class.forname(com.alvin.java.core.anno.fullannotest).getmethod(annotationtype); m0 = class.forname(java.lang.object).getmethod(hashcode); m3 = class.forname(com.alvin.java.core.anno.fullannotest).getmethod(value); } catch (nosuchmethodexception var2) { throw new nosuchmethoderror(var2.getmessage()); } catch (classnotfoundexception var3) { throw new noclassdeffounderror(var3.getmessage()); } }}我们看value()方法,这里调用了super.h对象,也就是invocationhandler对象,而我们注解用的是annotationinvocationhandler这个子类,我们在invoke方法中打个断点,就明白了~~

FIILRunner体验 299元的定价有着不错的性价比
城市排水管网监测的重要性及解决措施
谷歌亚马逊持续裁员,人工智能投资将成为重点
分享一种层状氧化物材料阳离子构型分析方法
动力电池比能量是什么_动力电池比能量密度怎么计算
JAVA中注解是怎么做到的(下)
基于WiFi+蓝牙模块的智能加热棒
集成电路产品EMC测试系统的测试项目有哪些 如何进行测试
物联网科技、人工智能、大数据推进的升级零售!
HIT 11: AI生成的作品著作权归属探讨
2021有方科技提交200余项专利 比亚迪推出四合一锁控MCU
C++代码需要遵循的10个最佳实践
苹果申请与汽车的自主导航系统有关的新专利
MAX9709 单声道/立体声、D类放大器
Valens联手英特尔代工服务,运用前沿工艺制造MIPI A-PHY芯片组
小米成为西班牙智能手机出货量第一
RTB2000数字示波器的特点特性及应用范围
阿里工业互联网平台“思考”:一场从0到1的蜕变
32国家投资641亿联合开发自己的超算和处理器,企图领先中美等
OpenHarmony 3.1 Beta版本关键特性解析——ArkUI开发框架容器类API的介绍与使用