Java自定义注解(Annotation)、元注解、注解处理器

注解为Java代码中各种程序元素(包、类、方法、成员变量、方法参数、本地变量等)提供了一种附加额外元数据(metadata)信息的能力。

如同Object类是所有类的默认父类一样,java.lang.annotation.Annotation接口是所有注解的默认父接口。

自定义注解

先来定义一个注解:

@Documented
@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationPet {
    String name() default "旺财";
}

元注解

Java SE提供了4个用于注解到其他自定义注解上的元注解

  • @Documented 用于生成JavaDoc文档。
  • @Inherited 使得父类上的注解信息能够通过继承关系传递到子类上。这种情况下,从父类和子类上得到的其实是同一个注解对象
  • @Target 接收一个ElementType[]数组,指明被修饰的注解可以标注在哪些地方,包类、方法、成员变量、方法参数等,详见ElementType枚举类。
  • @Retention 保留策略,标明该注解的有效范围,有SOURCE/CLASS/RUNTIME供3种,分别保留到源码、编译后的字节码文件和运行时。详见RetentionPolicy枚举类。

代码验证:

// Pet.java
@AnnotationPet
public class Pet {}
// Dog.java
public class Dog extends Pet {}

public static void main(String[] args) {
    // 因为@AnnotationPet注解上有@Inherited标记
    // 子类Dog并没有直接被@AnnotationPet注解,但是依然能获取到注解对象
    AnnotationPet annotation1 = Dog.class.getAnnotation(AnnotationPet.class);
    AnnotationPet annotation2 = Pet.class.getAnnotation(AnnotationPet.class);
    // 父类和子类上面的注解对象,其实是同一个对象
    System.out.println(annotation1 == annotation2);//true
    System.out.println(annotation1);//@AnnotationPet(name=旺财)
    
    // getDeclaredAnnotation忽略继承过来的注解,因此结果是null
    System.out.println(Dog.class.getDeclaredAnnotation(AnnotationPet.class));//null
    
    //Annotation接口是所有注解的默认父接口
    System.out.println(annotation1 instanceof Annotation);//true
	System.out.println(annotation1 instanceof Object);//true
}

注解中可以携带的元数据(metadata)类型:

注解中可以携带的元数据,是有特定类型限制的。并不是自己随便定义一个类都可以作为注解中元数据的类型。注解中支持的元数据类型如下:

  • 所有基本类型:boolean/byte/int/long/float等

  • String类型

  • Class类型

  • 自定义的enum枚举类型

  • Annotation类型

  • 以上类型的数组类型

注解处理器

如何通过Java代码来识别和处理注解中的信息呢?

Java反射包下面,有一个AnnotatedElement接口,其中定义了一些提取注解的方法:

// 提取特定类型annotationClass的注解对象,如果没有返回null
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
// 返回直接存在的(忽略继承过来的)特定类型的注解对象
<T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)
// 特定类型的注解是否存在
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
// 返回存在的所有注解
Annotation[] getAnnotations();
// 返回直接存在的(忽略继承过来的)所有注解
Annotation[] getDeclaredAnnotations();

AnnotatedElement接口的已知实现此接口的类包括:Class、Constructor、Field、Method、Package

也就是说,通过反射拿到Class/Constructor/Field/Method/Package对象后,就可以直接调用相关方法来获取到存在的注解对象。

final Class<?> clazz = Dog.class;
if(clazz.isAnnotationPresent(AnnotationPet.class)) {
    final AnnotationPet annotation = clazz.getAnnotation(AnnotationPet.class);
    System.out.println("注解中的元数据:name=" + annotation.name());
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值