注解

Annotation

  • 注解如同标签
  • 对类行为的某些角度进行评价与解释
  • 注解通过反射获取

    注解的创建

    1
    2
    public @interface TestAnnotation{
    }

注解的使用

1
2
3
@TestAnnotation
public class Test{
}

元注解

可以注解到其他注解上的注解,也就是基本注解,可以用来规范注解的一些行为

  • @Retention –> 注解的存活周期
    • RetentionPolicy.SOURCE 注解将被编译器丢弃
    • RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃
    • RetentionPolicy.RUNTIME VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息。
  • @Documented –> 能将注解保存到Javadoc中
  • @Target –> 注解应用的地方
    • ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
    • ElementType.CONSTRUCTOR 可以给构造方法进行注解
    • ElementType.FIELD 可以给属性进行注解
    • ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
    • ElementType.METHOD 可以给方法进行注解
    • ElementType.PACKAGE 可以给一个包进行注解
    • ElementType.PARAMETER 可以给一个方法内的参数进行注解
    • ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
  • @inherited –> 如果父类使用了此注解,那么子类可以继承此注解

    1
    2
    3
    4
    5
    6
    7
    8
    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    @interface Test {}

    @Test
    public class A {}

    public class B extends A {}
  • @Repeatable –> Java8新注解,多次应用的注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @interface Persons {
    Person[] value();
    }

    @Repeatable(Persons.class)
    @interface Person{
    String role default "";
    }

    @Person(role="artist")
    @Person(role="coder")
    @Person(role="PM")
    public class SuperMan{
    }

容器注解

存放注解的容器,本身也是注解。

注解的属性

注解的属性也叫做成员变量。

  • 注解只有成员变量,没有方法
  • 以无参的方法来声名
  • 方法名为成员名
  • 返回值为成员类型
    • 类型必须是 8 种基本数据类型
    • 接口
    • 注解
    • 以上各类型的数组
      1
      2
      3
      4
      5
      6
      7
      8
      9
      @Target(ElementType.TYPE)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface TestAnnotation {

      int id();

      String msg();

      }

在使用注解的时候,应该为该注解的属性赋值:

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

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

1
2
3
4
5
6
7
8
9
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {

public int id() default -1;

public String msg() default "Hi";

}

因此在使用的时候无需再赋初值:

1
2
@TestAnnotation()
public class Test {}

如果注解中属性名为value,那么可以省略属性名直接赋值使用

1
2
3
4
5
6
public @interface Check {
String value();
}

@Check("hi")
int a;

内置注解

  • @Deprecated
  • @Override
  • @SuppressWarnings
  • @FunctionalInterface Java8新特性,函数式接口可以很容易转化为Lamda表达式。

    注解与反射

  • 首先可以通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解:

    1
    public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
  • 然后通过 getAnnotation() 方法来获取 Annotation 对象:

    1
    public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
  • 或者是 getAnnotations() 方法:

    1
    public Annotation[] getAnnotations() {}
  • 如果获取到的Annotation不为null,则可以调用它的属性方法了:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @TestAnnotation()
    public class Test {

    public static void main(String[] args) {

    boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);

    if ( hasAnnotation ) {
    TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);

    System.out.println("id:"+testAnnotation.id());
    System.out.println("msg:"+testAnnotation.msg());
    }
    }
    }

程序运行结果:

1
2
id:-1
msg:

注解的作用

  • 注解本身对程序运行没有直接关系
  • 注解的存在主要是为编译器或APT(Annotation Processing Tool)使用,而要使用的话需要开发者手动调用方法来提取并处理Annotation的信息

    总结

  • 注解的作用是取决于你想要它做什么