1. 注解定义

关于注解首先引入官方文档的一句话:Java 注解用于为 Java 代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的。Java 注解是从 Java5 开始添加到 Java 的。

通俗理解,视为标签。

2. 基本定义

使用 @interface 进行定义

3. 元注解

元注解是可以注解到注解上的注解,或者说元注解是一种基本注解。

元注解分别有@Retention、 @Target、 @Document、 @Inherited和@Repeatable(JDK1.8加入)五种。

@Retention

Retention英文意思有保留、保持的意思,它表示注解存在阶段是保留在源码(编译期),字节码(类加载)或者运行期(JVM中运行)。在@Retention注解中使用枚举RetentionPolicy来表示注解保留时期,或者说解释了注解的存活时间。

@Retention(RetentionPolicy.SOURCE),注解仅存在于源码中,在class字节码文件中不包含

@Retention(RetentionPolicy.CLASS), 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得

@Retention(RetentionPolicy.RUNTIME), 注解会在class字节码文件中存在,在运行时可以通过反射获取到

如果我们是自定义注解,则通过前面分析,我们自定义注解如果只存着源码中或者字节码文件中就无法发挥作用,而在运行期间能获取到注解才能实现我们目的,所以自定义注解中肯定是使用 @Retention(RetentionPolicy.RUNTIME)

@Documented

它的作用是能够将注解中的元素包含到 Javadoc 中去。ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举

@Target

Target 是目标的意思,@Target 指定了注解运用的地方。限定了使用场景。

@Target 有下面的取值

引用段落

1. ElementType.ANNOTATION_TYPE 可以给一个注解进行注解

2. ElementType.CONSTRUCTOR 可以给构造方法进行注解

3. ElementType.FIELD 可以给属性进行注解

4. ElementType.LOCAL_VARIABLE 可以给局部变量进行注解

5. ElementType.METHOD 可以给方法进行注解

6. ElementType.PACKAGE 可以给一个包进行注解

7. ElementType.PARAMETER 可以给一个方法内的参数进行注解

@Inherited

不是说注解本身会继承,而是指如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。

@Repeatable

Repeatable 自然是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所 以算是一个新的特性。

什么样的注解会多次应用呢?通常是注解的值可以同时取多个。

4. 注解的属性

注解的属性也叫做成员变量。注解只有成员变量,没有方法。

需要注意的是,在注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组

注解中属性可以有默认值,默认值需要用 default 关键值指定

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test{
int id() default -1;
String msg() default "Hello";
}

上面代码定义了 TestAnnotation 这个注解中拥有 id 和 msg 两个属性。在使用的时候,我们应该给它们进行赋值。

赋值的方式是在注解的括号内以 value="" 形式,多个属性之前用 ,隔开

@Test(id=1,msg="hello annotation")
public class TestAnnotation {
}

5. 注解的提取

注解与反射。

注解通过反射获取。首先可以通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解

public boolean isAnnotationPresent(Class extends Annotation> annotationClass) {}

然后通过 getAnnotation() 方法来获取 Annotation 对象。

public  A getAnnotation(Class annotationClass) {}

或者是 getAnnotations() 方法。

public Annotation[] getAnnotations() {}

前一种方法返回指定类型的注解,后一种方法返回注解到这个元素上的所有注解。

如果获取到的 Annotation 如果不为 null,则就可以调用它们的属性方法了。比如

@Test()
public class TestDemo {
public static void main(String[] args) {
boolean hasAnnotation = TestDemo.class.isAnnotationPresent(Test.class);
if ( hasAnnotation ) {
TestAnnotation testAnnotation = TestDemo.class.getAnnotation(Test.class);
System.out.println("id:"+testAnnotation.id());
System.out.println("msg:"+testAnnotation.msg());
}
}
}

6.注解的使用场景

提供信息给编译器: 编译器可以利用注解来探测错误和警告信息

编译阶段时的处理: 软件工具可以用来利用注解信息来生成代码、Html文档或者做其它相应处理。

运行时的处理: 某些注解可以在程序运行的时候接受代码的提取

值得注意的是,注解不是代码本身的一部分。