从零学习Java注解(一)

1、注解保留策略

public enum RetentionPolicy {
    /**
     * 注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃.
     * 这意味着:Annotation仅存在于编译器处理期间,编译器处理完之后,该Annotation就没用了
     */
    SOURCE,
 
    /**
     * 注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期.
     */
    CLASS,
 
    /**
     * 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在,
     * 保存到class对象中,可以通过反射来获取
     */
    RUNTIME
}

2、注解能用到哪里

public enum ElementType {
    /**
     * 类、接口(包括注解类型)或枚举声明
     */
    TYPE,
    
    /**
     * 注解类型声明
     */
    ANNOTATION_TYPE,
    
    /**
     * 字段声明(包括枚举常量)
     */
    FIELD,
    
    /**
     * 方法声明
     */
    METHOD,
    
    /**
     * 参数声明
     */
    PARAMETER,
    
    /**
     * 构造方法声明
     */
    CONSTRUCTOR,
    
    /**
     * 局部变量声明
     */
    LOCAL_VARIABLE,

    /**
     * 包声明
     */
    PACKAGE
}

3、和注解有关的Java原生API

java.lang.Class<T>

public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
如果存在该元素的指定类型的注解,则返回这些注解,否则返回 null。

Annotation[] getAnnotations()
返回此元素上存在的所有注解。

Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注解。

boolean isAnnotation()
如果此 Class 对象表示一个注解类型则返回 true。

boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
如果指定类型的注解存在于此元素上,则返回 true,否则返回 false。
java.lang.reflect.Constructor<T>

<T extends Annotation> T getAnnotation(Class<T> annotationClass)
如果存在该元素的指定类型的注解,则返回这些注解,否则返回 null。

Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注解。
java.lang.reflect.Field

<T extends Annotation> T getAnnotation(Class<T> annotationClass)
如果存在该元素的指定类型的注解,则返回这些注解,否则返回 null。
		  
Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注解。
java.lang.reflect.Method

<T extends Annotation> T getAnnotation(Class<T> annotationClass)
如果存在该元素的指定类型的注解,则返回这些注解,否则返回 null。

Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注解。

Annotation[][] getParameterAnnotations()
返回表示按照声明顺序对此 Method 对象所表示方法的形参进行注解的那个数组的数组。

4、小试牛刀

该Demo参考了这篇博客
假设你想模仿org.junit.Test写一个自己的注解类。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) // 该注解只能用在方法签名上面
public @interface Test {

  // 若值为false,表示使用该注解的那个方法将被忽略,即不想被执行
  boolean enabled() default true;
}

假设你还想自定义一个注解,用于标识测试人的一些信息。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) // 该注解只能用在类、接口(包括注解类型)或枚举声明上面
public @interface TesterInfo {

  enum Priority {
    LOW, MEDIUM, HIGH
  }

  Priority priority() default Priority.MEDIUM;

  String[] tags() default "";

  String createdBy() default "Liu Dehua";

  String lastModified() default "2019-06-03 18:00:00";
}

展示上述两个自定义注解的用法。

@TesterInfo(
    priority = Priority.HIGH,
    createdBy = "Xiaoming",
    tags = {"sales","test" },
    lastModified = "2019-6-03 15:28:00"
)
public class TestExample {

  @Test
  void testA() {
    if (true)
      throw new RuntimeException("This test always failed");
  }

  /**
   * 通过enabled = false告知注解解释器不要执行
   */
  @Test(enabled = false)
  void testB() {
    if (false)
      throw new RuntimeException("This test always passed");
  }

  @Test(enabled = true)
  void testC() {
    if (10 > 1) {
      // 省略
    }
  }

}

无论注解设计的多么完美,总需要一个“懂它”的注解解释器。

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class AnnotationInterpreter {

  public static void main(String[] args) throws Exception {

    System.out.println("Testing...");

    int passed = 0, failed = 0, count = 0, ignore = 0;

    // 硬编码.class文件不太好,项目中更常见的是扫描某些包中的所有类
    Class<TestExample> obj = TestExample.class;

    // 处理TesterInfo注解
    if (obj.isAnnotationPresent(TesterInfo.class)) {

      Annotation annotation = obj.getAnnotation(TesterInfo.class);
      TesterInfo testerInfo = (TesterInfo) annotation;

      System.out.printf("%nPriority :%s", testerInfo.priority());
      System.out.printf("%nCreatedBy :%s", testerInfo.createdBy());
      System.out.printf("%nTags :");

      int tagLength = testerInfo.tags().length;
      for (String tag : testerInfo.tags()) {
        if (tagLength > 1) {
          System.out.print(tag + ", ");
        } else {
          System.out.print(tag);
        }
        tagLength--;
      }

      System.out.printf("%nLastModified :%s%n%n", testerInfo.lastModified());

    }

    // 处理自定义的Test注解,注意不是org.junit.Test
    for (Method method : obj.getDeclaredMethods()) {

      if (method.isAnnotationPresent(Test.class)) {

        Annotation annotation = method.getAnnotation(Test.class);
        Test test = (Test) annotation;

        if (test.enabled()) {
          try {
            method.invoke(obj.newInstance());
            System.out.printf("%s - Test '%s' - passed %n", ++count, method.getName());
            passed++;
          } catch (Throwable ex) {
            System.out.printf("%s - Test '%s' - failed: %s %n", ++count, method.getName(), ex.getCause());
            failed++;
          }
        } else {
          System.out.printf("%s - Test '%s' - ignored%n", ++count, method.getName());
          ignore++;
        }
      }
    }

    System.out.printf("%nResult : Total : %d, Passed: %d, Failed %d, Ignore %d%n", count, passed, failed, ignore);

  }
}

执行结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值