b1cat`s

Java注解

Word count: 846Reading time: 3 min
2020/02/13

Java注解

一种特殊注释–注解

- 注释会被编译器忽略,而注解被编译器打包进class,因此注解是一种用作标注的元数据。

分为三类:

    1. 不会被编译进.class
    • @override:告诉编译器检查该方法是否正确实现了覆写
    • @SuppressWarnings:告诉编译器忽略此处警告
    1. 由工具处理.class文件使用的注解,比如有些工具会在加载class的时候,对class做动态修改,实现一些特殊功能
    • 这类注解会被编译进入.class文件,加载结束后不会存在于内存
    • 这类注解只被一些底层库使用,一般我们不必自己处理
    1. 程序中能够读取的注解,加载后一直存在于JVM,定义配置参数可以包括:
    • 所有基本类型
    • String
    • 枚举类型
    • 基本类型,String以及枚举的数组

定义注解:

- 使用`@interface`语法定义注解(Annotation),它的格式如下:
1
2
3
4
5
6
public @interface Report {
int type() default 0; //default设定一个默认值
String level() default "info";
String Value() default "";
}

元注解(用来修饰其他注解的注解)

  • 最常用的元注解是@Target

    • 使用@Target可以定义Annotation能够被应用于源码的哪些位置:

      • 类或接口: ElementType.TYPE;
      • 字段:ElementType.FILED;
      • 方法:ElementType.METHOD;
      • 构造方法:ElementType.CONSTRUCTOR;
      • 方法参数:ElementType.PARAMETER;
    • 如电话已注解@Report可用在方法上,我们必须添加一个@Target(ElementType.METHOD):

      1
      2
      3
      4
      5
      6
      @Target(ElementType.METHOD)
      public @interface Report{
      int type() default 0;
      String level default "info";
      String value() default "";
      }
    • 定义多个注解,可以用数组

      1
      2
      3
      @Target({
      ElementType.METHOD, ElementType.FIELD
      })
  • @Retention(定义注解的生命周期)

    • 仅编译器: RetentionPolicy.SOURCE;
    • 仅class文件: RetentionPolicy.CLASS; //默认为CLASS
    • 运行期:RetentionPolicy.RUNTIME;
  • @Repeatable(定义注解是否可重复)

1
2
3
@Report(type=1, level="debug")
@Report(type=2, level="warning")
public class Hello{}
  • Inherited(定义子类是否可以继承父类定义的注解)
    • 仅对@Target(ElementType.TYPE)类型有作用
    • 仅针对class的继承,对interface继承无效

处理注解

SOURCE类注解有编辑器使用,一般我们只使用,不编写。CLASS类型注解主要由底层工具库使用,涉及class加载,我们很少用到。只有RUNTIME类的注解不但使用还需要经常编写。

注解定义后也是一种class,继承自java.lang.annotation.Annotation,读取注解需要使用反射API

JAVA提供反射API读取注解的方法:
- 判断某个注解是否存在于class、Filed、Method、Constructor
- Class.isAnnotationPresent(Class)
- Filed.isAnnotationPresent(Class)
- Method.isAnnotationPresent(Class)
- Constructor.isAnnotationPresent(Class)

1
Person.class.isAnnotationPresent(Report.class); //判断@report是否存在 于Person类内

- 读取注解
    - Class.getAnnotation(Class)
    - Filed.getAnnotation(Class)
    - Method.getAnnotation(Class)
    - Constructor.getAnnotation(Class)
1
2
3
Reprot report = Person.class.getAnnotation(Report.class);
int type = report.type();
String level = report.level();

使用注解

注解如何使用,完全由程序自己决定。例如,JUnit是一个测试框架,会自动运行所有标记为@Test的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Range{
int min() default 0;
int max() default 255;
}

//使用注解
void check(Person person) throws ILLegalArgumentException, ReflectiveOperationException {
//遍历Person中所有Filed
for (Filed filed : person.getClass().getFiled()){
//读取注解
Range range = filed.getAnnotation(Range.class);
if(range != null){
Object value = filed.get(person);
if (value instanceof String){
String s = (String) value;
if(s.length()<range.min() || s.length() >range.max(){
throw new ILLegalArgumentException("Invalid filed :"+filed.getName());
}
}
}
}
CATALOG
  1. 1. Java注解
    1. 1.0.1. 一种特殊注释–注解
    2. 1.0.2. 定义注解:
    3. 1.0.3. 处理注解
    4. 1.0.4. 使用注解