Java注解又称Java标注,是Java语言5.0版本开始支持加入源代码的特殊语法元数据。Java语言中的类、方法、变量、参数和包等均可以被标注。和Javadoc不一样,Java标注能够经过反射获取标注内容。在编译器生成类文件时,标注能够被嵌入到字节码中。Java虚拟机能够保留标注内容,在运行时能够获取到标注内容。html
维基百科对java注解说的仍是比较到位了,不理解能够先看看后面,再回来看上面的定义就很清楚了。java
@Override
和
@Nullable
,注解实际就是添加在类、变量、方法、参数等前面的一个修饰符而已,能够理解成一个标签。
注解和注释不同,注释只能保留在源码阶段,用来对代码的解释或者说明,能够看作就是文本,可是注解不同,它能够保留到运行阶段,咱们能够把注解也理解成代码,注释性代码,它除了提供了对代码的解释说明,它还能跟代码同样提供功能操做,但它是被动性的,就是它能提供信息,可是须要咱们经过其余方式来获取,好比能够经过其余方式如反射在动态运行阶段获取注解的信息并使用。web
咱们直接点 @Override
注解进去看看就知道,一个注解是什么定义的。数组
这是@Override
注解的写法,先无论A和B,这个咱们后面会说,直接先看D,一个注解,须要使用 @interface
,就跟咱们的类须要用class修饰,接口用interface
修饰同样,只要用@interface
修饰的就是注解。app
因此,一个简单的注解能够以下定义。ide
1public @interface TestAnnotation {}
复制代码
使用:
函数
再看上图,还有A@Target
和B@Retention
两个“注解”,这种用来注解注解的注解咱们叫作元注解,若是注解理解成是一个标签的话,那么元注解就是比较特殊的标签,它只能用来对普通标签进行解释说明。工具
元注解有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。post
Retention 的英文意为保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间。spa
它有一下三种取值:
使用场景:这类注解提供信息给编译器,编译器能够利用注解来探测错误和警告信息,好比咱们的
@Override
使用场景:软件工具能够利用注解信息来生成代码,Html文档和作其余相应处理。
使用场景:能够获取到它们的信息并进行逻辑处理(这也是咱们常常用的,会配合反射使用)。
大概示例图以下:
Target
英语就是目标的意思,
@Target
指定了注解能够运用的地方,咱们前面说了注解能够用在类、方法、变量、参数和包等上面,若是咱们没有使用
@Target
元注解对注解进行解释说明,那么这个注解能够随意放在类、方法变量这些地方,咱们使用了
@Target
后 ,经过指定其能够运用的地方,规定其只能用在咱们指定的上。
@Target 参数是一个数组枚举 ElementType[]
1public enum ElementType {
2 /** Class, interface (including annotation type), or enum declaration */
3 TYPE, // 接口、类、枚举、注解
4
5 /** Field declaration (includes enum constants) */
6 FIELD, // 字段、属性、枚举的常量
7
8 /** Method declaration */
9 METHOD, // 方法
10
11 /** Formal parameter declaration */
12 PARAMETER,// 方法参数
13
14 /** Constructor declaration */
15 CONSTRUCTOR, //构造函数
16
17 /** Local variable declaration */
18 LOCAL_VARIABLE, //局部变量
19
20 /** Annotation type declaration */
21 ANNOTATION_TYPE, //注解
22
23 /** Package declaration */
24 PACKAGE, //包
25
26 /**
27 * Type parameter declaration
28 *
29 * @since 1.8
30 */
31 TYPE_PARAMETER,
32
33 /**
34 * Use of a type
35 *
36 * @since 1.8
37 */
38 TYPE_USE
39}
复制代码
使用:
1@Target(ElementType.FIELD) // 只能注解到一个属性上。
复制代码
1@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PACKAGE}) // 只能注解到属性、方法,包上。
复制代码
标记注解,没有成员,顾名思义,这个元注解确定是和文档有关。它的做用是可以将注解中的元素包含到 Javadoc 中去。
参考 Annotation深刻研究——@Documented注释使用
Inherited
是继承的意思,可是它并非说注解自己能够继承,而是说若是一个超类被 @Inherited 注解过的注解进行注解的话,那么若是它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。
下面简单经过一个Demo来演示一下:
@Inherited
元注解Human
类,使用咱们自定义注解@Test
Man
类继承至Human
类。@Test
注解Man
类也能获取到@Test
注解和参数,这就是由于其父类上的注解使用了@Inherited
元注解字面意思是可重复的,说明这个元注解可重复使用,咱们看到@Repeatable
注解的变量类型则是对应Annotation(接口)的泛型Class。
咱们先定义一个重复注解类:
再声明一个容器注解类
咱们就能够对@Tag
注解重复使用,能够看到没有使用@Repeatable
的注解重复使用就会报错
经过前面的示例咱们能够看到,咱们能够为咱们的注解添加属性,注解的属性也叫作成员变量。注解只有成员变量,没有方法。
注解的成员变量在注解的定义中以“无形参的方法”形式来声明,
其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型
反射中,经过getDeclaredMethod
来获取。
在注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组
注解中属性能够有默认值,默认值须要用 default 关键值指定。
前面基本已经演示过了,咱们仍是简单演示一下。
定义一个带有多个成员变量的注解:
1/**
2 * @author : EvanZch
3 * description:定义多个成员变量注解
4 **/
5
6@Target(ElementType.TYPE)
7@Retention(RetentionPolicy.RUNTIME)
8public @interface TestValueAnnotation {
9 String name() default "EvanZch";
10
11 int age();
12
13 int[] info();
14}
复制代码
使用:
1@TestValueAnnotation(name = "Evan", age = 18, info = {175, 65})
2public class AnnotationValueTest {
3
4 public static void main(String[] args) {
5 }
6
7}
复制代码
注解一般与反射一块儿使用,而反射就是在运行状态中,对于任意一个类,都能知道这个类的全部属性及方法,对于任何一个对象,都能调用他的任何一个方法和属性,这种动态获取新的及动态调用对象的方法的功能叫作反射.
对反射不熟悉的能够先看看Java反射以及在Android中的使用
注解经过反射获取。首先能够经过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解
1public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
复制代码
而后经过 getAnnotation() 方法来获取 Annotation 对象。
1 public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
复制代码
或者是 getAnnotations() 方法。
1public Annotation[] getAnnotations() {}
复制代码
前一种方法返回指定类型的注解,后一种方法返回注解到这个元素上的全部注解。
咱们经过前面的AnnotationValueTest类演示,获取AnnotationValueTest类上@TestValueAnnotation
注解的信息。
1public static void main(String[] args) {
2// 1、判断AnnotationValueTest类上是否有注解
3// 一、先拿到AnnotationValueTest的class对象
4 Class<?> annotationValueTestzz = AnnotationValueTest.class;
5 // 二、经过其class对象调用isAnnotationPresent进行判断
6 boolean isAnnotation = annotationValueTestzz.isAnnotationPresent(TestValueAnnotation.class);
7 System.out.println("AnnotationValueTest--isAnnotation=" + isAnnotation);
8// 若是有注解
9if (isAnnotation) {
10// 三、有注解拿到这个注解的Annotation对象
11 TestValueAnnotation annotation = annotationValueTestzz.getAnnotation(TestValueAnnotation.class);
12 // 四、经过annotation对象获取其成员变量
13 int age = annotation.age();
14 int[] infos = annotation.info();
15 String name = annotation.name();
16 System.out.println("AnnotationValueTest--age=" + age + ",info.length=" + infos.length + ",name=" + name);
17 }
复制代码
结果:
AnnotationValueTest
类上的
@TestValueAnnotation
注解中的全部属性信息。
关于注解的使用,在Android中很常见,好比咱们butterknife和retrofit库里面就大量使用注解来进行操做,咱们下一篇,经过一篇注解实战来写一个简易版本的butterknife,下一篇见!