Java注解你知多少?
注解,英文名Annotation。官方文档中对注解的定义是这样的:Java注解用于为Java代码提供元数据。作为元数据,注解不直接影响你的代码运行,但是也有一些类型的注解实际上可以用于这些目的。
Java注解是从 Java5 开始添加到 Java 里面的。看完这句话你可能对注解的定义还是一头雾水,接下来就和我一起结合案例来深入学习Java注解相关的知识吧
1. 什么是注解
日常开发中新建 Java 类,比较常见的有 class、interface 等,而注解同样也属于一种类,只不过它的修饰符是’@interface’。
一个注解准确意义上来说,只不过是一种特殊的注释而已,如果没有解析它的代码,它可能连注释都不是。
2。 元注解探秘
元注解是用于修饰注解的注解,通常用在注解的定义上。
Java 中元注解有以下几种形式:
@Target:注解的作用目标
@Inherited:是否允许子类继承该注解
@Retention:注解的生命周期
@Documented:注解是否应当被包含在 JavaDoc 文档中
@Repeatable:说明被这个元注解修饰的注解可以同时作用一个对象多次,每次作用注解代表不
同的含义
2.1 Target
@Target元注解表示我们的注解作用的范围就很大,有类,方法,方法参数变量等,还可通过枚举
类ElementType来表示作用类型。
@Target(ElementType.TYPE) 作用接口、类、枚举、注解。
@Target(ElementType.FIELD) 作用属性字段、枚举的常量。
@Target(ElementType.METHOD) 作用方法。
@Target(ElementType.PARAMETER) 作用方法参数。
@Target(ElementType.CONSTRUCTOR) 作用构造函数。
@Target(ElementType.LOCAL_VARIABLE) 作用局部变量。
@Target(ElementType.ANNOTATION_TYPE) 作用于注解(@Retention注解中就使用该属
性)。
@Target(ElementType.PACKAGE) 作用于包。
@Target(ElementType.TYPE_PARAMETER) 作用于类型泛型,即泛型方法、泛型类、泛型接口
(jdk1.8加入)。
@Target(ElementType.TYPE_USE) 类型使用.可以用于标注任意类型除了 class (jdk1.8加入)一
般比较常用的是ElementType.TYPE类型。
PS:@Target 用于指明被修饰的注解最终可以作用的目标是谁,也就是指明,你的注解到底是用来修饰
方法、修饰类亦或者是用来修饰字段属性的。
2.2 @Inherited
Inherited 的意思是继承,但是这个继承和我们平时理解的继承大同小异,一个被 @Inherited 注解
了的注解修饰了一个父类,如果他的子类没有被其他注解修饰,则它的子类也继承了父类的注解。
2.3 @Retention
Retention有保留、保持的意思,它表示注解存在阶段是保留在源码(编译期),字节码(类加载)
或者运行期(JVM中运行)。在@Retention注解中使用枚举RetentionPolicy来表示注解保留时期。
@Retention(RetentionPolicy.CLASS), 默认的保留策略,注解会在class字节码文件中存在,但
运行时无法获得。
@Retention(RetentionPolicy.SOURCE),注解仅存在于源码中,在class字节码文件中并不包
含。
@Retention(RetentionPolicy.RUNTIME), 注解会在class字节码文件中存在,在运行时可以通
过反射获取到。
如果我们是自定义注解,则通过前面分析,我们自定义注解如果只存着源码中或者字节码文件中就
无法发挥作用,而在运行期间能获取到注解才能实现我们目的,所以自定义注解中肯定是使用
@Retention(RetentionPolicy.RUNTIME)。
2.4 @Documented
Document的英文意思是文档。它的作用是能够将注解中的元素包含到 Javadoc 中去。
9.2.5 @Repeatable
Repeatable表示可重复的。从字面意思来理解就是说明被这个元注解修饰的注解可以同时作用一个
对象多次,但是每次作用注解又可以代表不同的含义。
3.注解属性知多少
注解的属性其实和类中定义的变量有异曲同工之处,只是注解中的变量都是成员变量(属性),并且注
解中是没有方法的,只有成员变量,变量名就是使用注解括号中对应的参数名,变量返回值注解括号中
对应参数类型。相信这会你应该会对上面的例子有一个更深的认识。而 @Repeatable 注解中的变量则类
型则是对应 Annotation(接口)的泛型 Class。
4.注解的本质
注解的本质就是一个Annotation接口
从上述代码中我们可以看出,注解本身就是Annotation接口的子接口,也就是说注解中其实是可以有属
性和方法,但是接口中的属性都是static final的,对于注解来说没什么意义,而我们定义接口的方法就相
当于注解的属性,也就对应了前面说的为什么注解只有属性成员变量,其实他就是接口的方法,这就是
为什么成员变量会有括号,不同于接口我们可以在注解的括号中给成员变量赋值。
4.2 注解属性类型
基本数据类型
String
枚举类型
注解类型
Class类型
以上类型的一维数组类型
4.3 为注解成员变量赋值
如果注解又多个属性,则可以在注解括号中用“,”号隔开分别给对应的属性赋值,如下例子,注解在父类
中赋值属性。
4.4 获取注解的属性
前面我们说了很多注解如何定义,放在哪,现在我们可以开始学习注解属性的提取了,这才是使用注解
的关键,获取属性的值才是使用注解的目的。如果获取注解属性,当然是反射啦,主要有三个基本的方
法:
下面结合前面的例子,我们来获取一下注解属性,在获取之前我们自定义的注解必须使用元注解
@Retention(RetentionPolicy.RUNTIME)
5.JDK提供的注解
6.注解的运用
如果你是一名Android 开发者,平常所使用的第三方框架ButterKnife,Retrofit2,Dagger2等都有注解的应用,如果想要了解这些框架的原理,则注解的基础知识则是必不可少的。
7.注解的意义
提供信息给编译器: 编译器可以利用注解来检测出错误或者警告信息,打印出日志。
编译阶段时的处理: 软件工具可以用来利用注解信息来自动生成代码、文档或者做其它相应的自动处理。
运行时处理: 某些注解可以在程序运行的时候接受代码的提取,自动做相应的操作。
正如官方文档的那句话所说,注解能够提供元数据,转账例子中处理获取注解值的过程是我们开发者直接写的注解提取逻辑,处理提取和处理 Annotation 的代码统称为 APT(AnnotationProcessing Tool)。上面转账例子中的processAnnotationMoney方法就可以理解为APT工具类。