疯狂Java讲义读书笔记14 Annotation(注释)
------------恢复内容开始------------
从jdk5开始Java增加了对元数据的支持,也就是Annotation,这种Annotation与第三章介绍的注释有区别,本章介绍的Annotation其实是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。
通过使用注解,程序开发人员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充的信息。代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证或者进行部署。
Annotation提供了一种为程序元素设置元数据的方法,从某些方面来看Annotation就像修饰符一样,可以用于修饰包、类、构造器、方法、成员变量、参数、局部变量的声明,这些信息被存储在Annotation的“name = value”对中。
Annotation是一个接口,程序可以通过通过反射来获取指定程序元素的Annotation对象,然后通过Annotation对象来获取注解里的元数据。读者需要注意本章中使用Annotation的地方,有的Annotation指的是java.lang.Annotation接口,有的指的是注解本身。
Annotation能被用来为程序元素(类、方法、成员变量等)设置元数据。值得指出的是,Annotation不影响程序代码的执行,无论增加、删除Annotation,代码都始终如一地执行。如果希望让程序中的Annotation在运行时起一定的作用,只有通过某种配套的工具对Annotation中的信息进行访问和处理,访问和处理Annotation的工具称为APT(Annotation Processing Tool)
基本Annotation
Annotation必须使用工具来处理,工具负责提取Annotation里包含的元数据,工具还会根据这些元数据增加额外的功能。
在系统学习新的Annotation语法之前,先看一下Java提供的5个基本Annotation的用法
使用Annotation时要在其前面增加@符号,并把该Annotation当成一个修饰符使用,用于修饰它支持的程序元素。
5个基本的Annotation如下:

上面5个基本Annotation中的@SafeVarags是Java7新增的
@FunctionalInterface是Java8新增的
限定重写父类方法
@Override就是用来重写指定的方法覆盖的,它可以强制一个子类必须覆盖父类方法。
编译程序丝毫看不出程序中的@Override有什么作用,因为@Override的作用就是告诉编译器检查这个方法,保证父类要包含一个该方法的重写方法,否则就会编译出错。
主要就是帮助程序员避免一些低级的错误。
@Override只能修饰方法,不能修饰其他程序元素
标识已过时:@Deprecated
@Deprecated用于表示某个程序元素(类、方法)已过时,当其他程序使用已过时的类,方法时,编译器会给出警告
抑制编译器警告
@SuppressWarnings
指示该Annotation修饰的程序元素取消指定的编译器警告
@SuppressWarnings会一直作用于该程序元素的所有子元素
java7的堆污染警告与@SafeVarargs
当把一个不带泛型的对象赋值给一个带泛型的变量时,往往就会发生这种堆污染。
不想看到警告就可以加这个注解
Java8的函数式接口与@FunctionalInterface
Java8规定:如果接口中只有一个抽象方法(可以包含多个默认方法或多个static方法),该接口就是函数式接口
@FunctionalInterface就是用来指定某个接口必须是函数式接口
JDK的元Annotation
JDK除了在java.lang下提供了五个基本的Annotation之外,还在java.lang.annotation包下提供了6个Meta Annotation(元Annotation),其中五个元Annotation都用于修饰其他的Annotation定义。
其中@Repeatable专门用于定义java8新增的重复注解,本章后面会重点介绍相关的内容。此处先介绍常用的4个元Annotation
1、@Rentention
@Rentention只能修饰Annotation定义,用于指定修饰的Annotation可以保留多长时间
@Rentention包含一个RetentionPolicy类型的value成员变量,所以使用@Rentention时必须为该value成员变量赋值

如果需要通过反射获取注解信息,就需要使用value属性值为RetentionPolicy.RUNTIME的@Retention

如果使用注解时只需要为value成员变量指定值,则使用该注解时可以直接在该注解后的括号里指定value成员变量的值,无需使用value=变量值的形式
@Target
@Target也只能修饰一个Annotation定义,它用于指定被修饰的Annotation能用于修饰哪些程序单元。
这个注解也只包含一个名为value的成员变量,该成员变量的值只能是如下几个


如下代码指定的value值只能修饰成员变量。
3、使用Documented
用于指定Annotation将被javadoc提取文档。

4、使用Inherited
@Inherited元Annotation指定被它修饰的Annotation将具有继承性
如果某个类使用了@Xxx注解(定义该Annotation时使用了@Inherited修饰)修饰,则起子类将自动被@Xxx修饰
自定义Annotation
前面已经介绍了如何使用java.lang包下的4个基本的Annotation,下面介绍如何自定义Annotation,并利用Annotation来完成一些实际的功能。
1、定义Annotation
定义新的Annotation类型使用@interface关键字

可能有读者看出,上面定义Annotation的代码与定义接口的语法非常像,只是MyTag使用@interface关键字来定义,而接口使用interface来定义。
使用@interface定义的Annotation的确非常像定义了一个注解接口。这个注解继承了Annotation接口,这一点可以通过反射看到MyTag接口里包含了Annotation接口里的方法。
一旦在Annotation里定义了成员变量之后,使用该Annotation时就应该为该Annotation的成员变量指定值。

也可以在定义Annotation的成员变量时为其指定初始值(默认值),指定成员变量的初始值可以使用default关键字。如下代码定义了@MyTag Annotation,该Annotation里包含了两个成员变量:name和age,这两个成员变量使用default指定了初始值。

如果为Annotation的成员变量指定了默认值,使用该Annotation时则可以不为这些成员变量指定值,而是直接使用默认值。

当然也可以在使用MyTag Annotation时为成员变量指定值,如果为MyTag的成员变量指定了值,则默认值可能不会起作用。
根据Annotation是否可以包含成员变量,可以把Annotation分为如下两类。
标记Annotation:如Override或Test,他们仅利用自身的存在与否提供信息
元数据Annotation:包含成员变量的Annotation,因为他们可以接受更多的元数据,所以也被称为元数据Annotation。
提取Annotation信息
使用Annotation修饰了类、方法、成员变量等成员后,这些Annotation不会自己生效,必须由开发者提供相应的工具来提取并处理Annotation
Java使用Annotation接口来代表程序元素前面的注解,该接口是注解的父接口。

浙公网安备 33010602011771号