注解原来是这么实现的

文章来源:一氧化碳中毒   发布时间:2021-8-2 12:11:41   点击数:
  

不点蓝字,我们哪来故事?

Java注解是在JDK1.5被引入的技术,配合反射可以在运行期间处理注解,配合apttool可以在编译器处理注解,在JDK1.6之后,apttool被整合到了javac里面。

什么是注解注解其实就是一种标记,常常用于代替冗余复杂的配置(XML、properties)又或者是编译器进行一些检查如JDK自带的Override、Deprecated等,但是它本身并不起任何作用,可以说有它没它都不影响程序的正常运行,注解的作用在于「注解的处理程序」,注解处理程序通过捕获被注解标记的代码然后进行一些处理,这就是注解工作的方式。

在java中,自定义一个注解非常简单,通过

interface就能定义一个注解,实现如下

public

interfacePrintMsg{}写个测试类给他加上我们写的这个注解吧

PrintMsgpublicclassAnnotationTest{publicstaticvoidmain(String[]args){System.out.println("annotationtestOK!");}}我们发现写与不写这个注解的效果是相同的,这也印证了我们说的注解只是一种「标记」,有它没它并不影响程序的运行。

元注解在实现这个注解功能之前,我们先了解一下元注解。

元注解:对注解进行注解,也就是对注解进行标记,元注解的背后处理逻辑由apttool提供,对注解的行为做出一些限制,例如生命周期,作用范围等等。

Retention用于描述注解的生命周期,表示注解在什么范围有效,它有三个取值,如下表所示:

类型作用SOURCE注解只在源码阶段保留,在编译器进行编译的时候这类注解被抹除,常见的

Override就属于这种注解CLASS注解在编译期保留,但是当Java虚拟机加载class文件时会被丢弃,这个也是

Retention的「默认值」。

Deprecated和

NonNull就属于这样的注解RUNTIME注解在运行期间仍然保留,在程序中可以通过反射获取,Spring中常见的

Controller、

Service等都属于这一类

Target用于描述注解作用的「对象类型」,这个就非常多了,如下表所示:

类型作用的对象类型TYPE类、接口、枚举FIELD类属性METHOD方法PARAMETER参数类型CONSTRUCTOR构造方法LOCAL_VARIABLE局部变量ANNOTATION_TYPE注解PACKAGE包TYPE_PARAMETER1.8之后,泛型TYPE_USE1.8之后,除了PACKAGE之外任意类型

Documented将注解的元素加入Javadoc中

Inherited如果被这个注解标记了,被标记的类、接口会继承父类、接口的上面的注解

Repeatable表示该注解可以重复标记

注解的属性除了元注解之外,我们还能给注解添加属性,注解中的属性以无参方法的形式定义,方法名为属性名,返回值为成员变量的类型,还是以上述注解为例:

首先给这个注解加亿点点细节,生命周期改为Runtime,使得运行期存在可以被我们获取

Retention(RetentionPolicy.RUNTIME)public

interfacePrintMsg{intcount()default1;Stringname()default"mynameisPrintMsg";}

PrintMsg(count=)publicclassAnnotationTest{publicstaticvoidmain(String[]args){//通过反射获取该注解PrintMsgannotation=AnnotationTest.class.getAnnotation(PrintMsg.class);System.out.println(annotation.count());System.out.println(annotation.name());}}输出如下:

mynameisPrintMsg到这里就有两个疑问了:

getAnnotation获取到的是什么?一个实例?注解是一个类?我们明明调用的是count(),name(),但是为什么说是注解的属性?等下聊

到底什么是注解?按照注解的生命周期以及处理方式的不同,通常将注解分为「运行时注解」和「编译时注解」

运行时注解的本质是实现了Annotation接口的特殊接口,JDK在运行时为其创建代理类,注解方法的调用实际是通过AnnotationInvocationHandler的invoke方法,AnnotationInvocationHandler其中维护了一个Map,Map中存放的是方法名与返回值的映射,对注解中自定义方法的调用其实最后就是用方法名去查Map并且放回的一个过程编译时注解通过注解处理器来支持,而注解处理器的实际工作过程由JDK在编译期提供支持,有兴趣可以看看javac的源码运行时注解原理详解之前我们说注解是一种标记,只是针对注解的作用而言,而Java语言层面注解到底是什么呢?以JSL中的一段话开头

?

Anannotationtypedeclarationspecifiesanewannotationtype,aspecialkindofinterfacetype.Todistinguishanannotationtypedeclarationfromanormalinterfacedeclaration,thekeywordinterfaceisprecededbyanat-sign(

).

?简单来说就是,注解只不过是在interface前面加了

符号的特殊接口,那么不妨以PrintMsg.class开始来看看,通过javap反编译的到信息如下:

publicinterface

转载请注明:http://www.lwblm.com/bzbk/12234.html
  • 上一篇文章:
  • 下一篇文章: 没有了