美文网首页
10.注解(Thinking in java学习十)

10.注解(Thinking in java学习十)

作者: Vinson武 | 来源:发表于2020-04-16 14:03 被阅读0次

基本概念

  1. 定义:注解(也称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。

  2. 注解在一定程度上是在把元数据和元代码文件结合在一起。通过使用注解,我们可以把这些元数据保存在Java源代码中,并利用annotation API为自己的注解构造处理工具。

  3. Java内置了三种定义在java.lang中的注解

  • @Override,覆盖超类
  • @Deprecated,过期注释
  • SuppressWarnings,关闭不当的编译器的警告信息。

另外还提供了==四种元注解==,专门负责新注解的创建。

  • @Targer:表示该注解可以用于什么地方。
  • @Retention:表示需要在什么级别保存该注解信息。
  • @Documented:将此注解包含在Javadoc中。
  • @Inherited:允许子类继承父类中的注解。

@Targer


image.png

@Retention


image.png

基本语法

定义注解

@Targer(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserCase{
   //注解元素
    public int id();
    public String desc() default "no desc"; //默认值
}

注解的定义看起来很像接口的定义,注解也将会编译成class文件。

注解的元素看起来就像接口的方法,唯一的区别是你可以为其指定默认值。

没有元素的注解称为标记注解。

注解使用

public class Test{
    @UserCase(id = 47, desc = "xxxx")
    public boolean testMet(String str){
        ...
        return true;
    }
}

注解的元素在使用时表现为名-值对的形式,并需要置于@UserCase声明之后的括号内。

编写注解处理器

注解元素

注解元素的类型有以下几种:

  • 所有基本类型(int, float等)
  • String
  • Class
  • enum
  • Annotation(注解)
  • 以上类型的数组

如果使用其他类型,编译器会报错。注意,也不能使用包装类型。

默认值限制

编译器对注解元素默认值要求较高

  • 首先,元素不能有不确定的值。即元素要么具有默认值,要么在使用注解时提供元素的值。
  • 其次,对于非基本类型的元素,定义默认值都不能以null作为其值。(这个约束使得处理器很难表现一个元素的存在或缺失,只能自己定义一些特殊值,比如空字符串或负数来表示元素不存在)

注解不支持继承,不能使用关键字extends来继承某个@interface。

实现处理器

一个简单的原始注解处理器

public class UseCaseTraker{
    public static void useCaseTrakers(List<Integer> useCases, Class<?>cl){
        for(Method m : cl.getDeclaredMethods()){
            UseCase uc = m.getAnnotation(UseCase.class);
            if(uc !=null){
                System.out.println(uc.id() + " " + uc.desc());
                useCase.remove(new Integer(uc.id()));
            }
        }
        for(int i:useCase){
            System.out.println("current case " + i);
        }
    }
    public static void main(String[] args){
        List<Integer>useCase = new ArrrayList<Integer>();
        Collections.addAll(useCase, 47, 48);
        trackUseCase(useCase, Test.class);
    }
}
//输出: 47 xxxx
//current case 48

getAnnotation(Class<A> annotationClass)获得注解

getDeclaredAnnotations()获得注解元素

Java自定义注解是通过运行时靠反射获取注解

处理器的写法有固定的套路,继承AbstractProcessor。

public class MyProcessor extends AbstractProcessor {
 
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
    //当我们编译程序时注解处理器工具会调用此方法并且提供实现ProcessingEnvironment接口的对象作为参数。
        super.init(processingEnv);
    }
 
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types = new LinkedHashSet<>();
        types.add(UserCase.class.getCanonicalName());//返回该注解处理器支持的注解集合
        return types;

    }
 
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
 
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        //处理注解
        return true;
    }
}
  • init(ProcessingEnvironment processingEnv) 被注解处理工具调用,参数ProcessingEnvironment 提供了Element,Filer,Messager等工具
  • getSupportedAnnotationTypes() 指定注解处理器是注册给那一个注解的,它是一个字符串的集合,意味着可以支持多个类型的注解,并且字符串是合法全名。
  • getSupportedSourceVersion 指定Java版本
  • process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) 这个也是最主要的,在这里扫描和处理你的注解并生成Java代码,信息都在参数RoundEnvironment 里了。

注册注解处理器


image.png

google提供了一个注册处理器的库

compile 'com.google.auto.service:auto-service:1.0-rc2'

一个注解搞定:

@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor {
      ...
}

相关文章

网友评论

      本文标题:10.注解(Thinking in java学习十)

      本文链接:https://www.haomeiwen.com/subject/koyrvhtx.html