第二章注解深入浅出(一、注解 Annotations)

第二章注解深入浅出

  • 一、注解 Annotations
    • 1.1 注解
    • 1.2 元注解
    • 1.3 自定义注解

一、注解 Annotations

1.1 注解

注解是一种将元数据附加到代码中的方法。

注解(Annotation),也叫做元数据,一种代码级别的说明。 它是 JDK 1.5 及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明、注解。

Java 注解:声明注解需要在类前面使用 @interface 关键字:

public @interface MyAnnotation {
}

Kotlin 注解:声明注解需要在类前面使用 annotation 关键字:

annotation class MyAnnotation

Android 注解的好处:

  • 简化代码,提高开发效率(不一定提高运行效率)
  • 更早的发现程序的问题或者错误
  • 更好的增加代码的描述能力
  • 更加利于我们的一些规范约束
  • 提供解决问题的更优解

1.2 元注解

元注解是用来定义其他注解的注解,简单来说,就是注解上的注解。

元注解共有四种:@Rentention、@Target、@Inherited、@Documented。

@Retention:注解保留的声明周期,默认值为 CLASS。对应 RetentionPolicy 的枚举,表示注解在何时生效,可选值有三种

  • SOURCE:只在源码中可用(当 Java 文件编译成 Class 文件的时候,注解被遗弃)
  • CLASS:在源码和字节码中可用(Jvm 加载 Class 文件的时候被遗弃,这是默认的声明周期)
  • RUNTIME:在源码、字节码和运行时均可用(Jvm 加载到 Class 文件之后,仍然存在)
    SOURCE < CLASS < RUNTIME,前者能作用的地方后者一定也能作用。

@Target:注解对象的作用范围,对应 ElementType 枚举,明确了注解的有效范围。ElementType 枚举中包括:

  • TYPE:类、接口、枚举、注解类型
  • FIELD:类成员(构造方法、方法、成员变量)
  • METHOD:方法
  • PARAMETER:方法参数
  • CONSTRUCTOR:构造函数
  • LOCAL_VARIABLE:局部变量
  • ANNOTATION_TYPE:注解
  • PACKAGE:包
  • TYPE_PARAMETER:类型参数
  • TYPE_USE:类型使用声明

@Inherited:注解是否可以被继承,默认为 false。用 @Inherited 声明出来的注解只对类有效,对方法/属性无效。

@Document:是否会保存到 Javadoc 文档中。

现在来看下 @Override 注解的源码:

package java.lang;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.METHOD})
public @interface Override {
}

分析一下,
@Retention(RetentionPolicy.SOURCE):表示 @Override 注解只在源码中使用,
@Target({ElementType.METHOD}):表示 @Override 注解作用的范围在方法中,也就是用来修饰方法的。

1.3 自定义注解

自定义注解的时候,需要使用到元注解来定义我们自定义的注解。

举个例子讲解。

package com.example.demo;import java.lang.annotation.Retention;
import java.lang.annotation.Target;import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;@Retention(RUNTIME)
@Target(FIELD)
public @interface TestAnnotation {String value();String[] value2() default "value2";}

注解值的写法:类型 参数名() default 默认值;
其中默认值是可选的,可以定义,也可以不定义。

处理运行时注解

Rentention 的值为 RUNTIME 时,注解会保留到运行时,因此使用反射来解析注解。

还是用上一步的注解 @TestAnnotation,解析示例如下:

package com.example.demo;import java.lang.reflect.Field;public class Demo {@TestAnnotation("Hello Annotation")private String testAnnotation;public static void main(String[] args) {try {// 获取要解析的类Class clazz = Class.forName("myAnnotaiton.Demo");// 拿到所有 FiledField[] declaredFields = clazz.getDeclaredFields();for (Field field : declaredFields) {// 获取 Field 上的注解TestAnnotation testAnnotation = field.getAnnotation(TestAnnotation.class);if (null != testAnnotation) {// 获取注解值String value = testAnnotation.value();System.out.println("value = " + value);}}} catch (ClassNotFoundException e) {e.printStackTrace();}}
}