前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Retrofit解析4之注解

Retrofit解析4之注解

作者头像
隔壁老李头
发布2018-08-30 11:47:39
1.3K0
发布2018-08-30 11:47:39
举报
文章被收录于专栏:Android 研究Android 研究

由于Retrofit里面大量的用到了注解,为了让大家更好的学习Retrofit,特意准备了一篇Java注解,如果大家已经对Java注解已经很熟悉了,就略过,看下一篇文章 本篇文章主要讲解

  • 1、Java 注解技术基本概念
  • 2、Java 元注解
  • 3、标准注解/内建注解
  • 4、自定义注解
  • 5、注解处理器
  • 6、注解思维导图
  • 7、注解原理

一、Java注解技术基本概念

(一) 什么是注解

Annotation是java 5开始引入的新特征。中文名称一般叫注解。它提供了一种安全的类似于注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。

上面的类似官方的解释,那我们再来通俗的解释一下: 我们都知道在Java代码中使用注解是为了提升代码的可读性,也就是说,注释是给人看的(对编译器来说是没有意义上的)。注解可以看做注释的"加强升级版",它可以向编译器、虚拟机等解释说明一些事情(也就是说它对编译器等工具也是"可读"的)。比如我们非常熟悉的@Overrider 注解,它的作用是告诉编译器它所注解的方法是重写父类中的方法,这样编译器就会检查父类是否存在这个方法,以及这个方法的签名与父类是否相同。 也就是说,注解是描述Java代码的代码,它能够被编译器解析,注解处理工具在运行时也能够解释注解。除了向编译器等传递一些信息,我们也可以用注解生成代码。比如我们可以用注解描述我们的意图,然后让注解解析工具来解析注解,以此来生成一些"模板化"的代码。注解是一种"被动"的信息,必须有编译器或虚拟机来"主动"解析它,它才能发挥自己的作用。

(二) 什么是元数据(metadata)

元数据由metadata翻译来的,所谓元数据就是"关于数据的数据",更通俗的说就是描述数据的数据的,对数据及信息资源的描述性信息,比如一个文本文件,有创建时间、创建人、文件大小等数据,都是可以理解为是元数据。在java中,元数据以标签的形式存在java代码中,它的存在并不影响程序代码的编译和执行,通常它被用来生成其他的文件或运行时知道被运行代码的描述信息。java代码中的javadoc和注解都属于元数据。

(三) 注解的前世今生

注解首先在第三版的Java Language Specification中被提出,并在Java 5中被实现。

(四)为什么要使用注解

  • 1、在未使用Annotation之前(甚至是使用之后),一般使用XML来应用于元数据的描述。不是何时开始一些开发人员和架构师发现XML的维护原来越复杂和糟糕,他们希望使用一些和代码紧密耦合的东西,而不是像XML一样是松耦合的(在某些情况下甚至是完全分离的)代码描述。如果你在百度或者google中搜索"xml vs annotations",就会看到关于这个话题的辩论。因为XML的配置就是为了分离代码和配置而设置的。但是用Annotation(注解)还是XML各有利弊。(下面有举例说明)
  • 2、另外一个很重要的因素是Annotation注解定义一种标准的描述元数据的方式。在这之前,开发者通常使用他们自己的方式定义元数据。例如,使用标记interface,注释,transient关键字等。每个程序员都用自己的方式定义元数据,而不像Annotation这种标准的方式。

下面我简单举例说明。 比如,你想为你的应用设置很多常量或参数,这种情况下,XML是一个很好的选择,因为它不会与特定的代码关联。如果你想把某个方法声明为服务,那么使用Annotation会更好一些,因为这种情况下需要注解和方法高度耦合一起。

因为XML是松耦合的,注解是紧耦合的,所以目前主流的框架将XML和Annotation两种方式结合使用,平衡两者之前的利弊。 在需要高度耦合的地方,Annotation注解比XML更容易维护,阅读更方便 在需要松耦合的地方,使用XML更方便 在某个方法声明为服务时,这种紧耦合的情况下,比较适合Annation注解。

(五)、注解的作用

Annotation 注解 通常被用以作以下目的:

  • 1、编译器指令
  • 2、构建时指令
  • 3、运行时指令 Java 内置了三种编译器指令,Java注解可以应用于构建时,即当你构建你的项目时,构建的过程包括产生源代码、编译源代码、产生xml文件,将编译过的代码或者文件打包进jar文件等。通常情况下,注解不会出现在编译之后的Java代码中,但是想要出现也是可以的。Java支持运行时注解。这些注解可以通过java反射访问,运行时注解主要是提供给程序或者第三方API一些指令。
(六) 注解基础

一个简单的Java注解 类似于下面的这种 @Doctor ,"@" 符号告诉编译器这是一个注解,跟在"@" 符号后面的是注解的名字,上述的例子中注解的名字是Doctor。

(七) 注解元素

Java 注解可以使用元素设置一些值,元素类似于属性或者参数。下面是一个包含元素注解的例子

代码语言:javascript
复制
@Doctor (name = "张三")

上述注解的元素名称是name,值是"张三",没有元素的注解不需要括号。注解可以包含多个元素,下面就是包含多个元素的例子

代码语言:javascript
复制
@Doctor(name = "张三", sex= "男")

当注解只包含一个元素时,你可以省去写元素的名字,直接赋值即可。下面的例子就是直接赋值。

代码语言:javascript
复制
@InsertNew("yes")
(八)注解使用

Annotation 注解可以在以下场合被使用到

  • 接口
  • 方法
  • 方法参数
  • 属性
  • 局部变量

二、元注解

(一) 什么是元注解

元注解,元注解就是负责注解其它注解.Java5.0定义了4个标准的meta-annotation类型,它们呗用来提供对其他annotation类型作说明。Java5.0定义的元注解:

  • @Target
  • @Retention
  • @Documented
  • @Inherited

这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们来看一下每一个元注解的作用和说明

1、@Target

表示该注解可以用在什么地方,由ElementType枚举定义

  • CONSTRUCTOR:构造器的声明
  • FIELD:域声明(包括enum实例)
  • LOCAL_VARIABLE:布局变量声明
  • METHOD:方法声明
  • PACKAGE:包声明
  • PARAMETER:参数声明
  • TYPE:类、接口(包括注解类型)或enum声明
  • ANNOTATION_TYPE:注解声明(应用于另一个注解上)
  • TYPE_PARAMETER:类型参数声明(1.8新加入)
  • TYPE_USE:类型使用声明(1.8新加入) PS: 当注解未制定Target值时,此注解可以使用任何元素之上,就是上面的类型。

举例如下:

代码语言:javascript
复制
@Target(ElementType.METHOD)
public @interface MethodInfo { 
}

上面代码中我们使用"@Target"元注解来说明MethodInfo这个注解只能应用于对方法进行注解。

2、@Retention

表示需要在什么级别保存该注解信息,由RetentionPolicy枚举定义

  • SOURCE:注解将编译器丢弃(该类型的注解信息只会保留在源码里,源码经过编译后,注解信息会被丢弃,不会保留在编译好的class文件里)
  • CLASS:注解在class中可用,但会被VM丢弃(该类型的注解信息会保留在源码里和class文件里,在执行的时候,不会加载到虚拟机中(JVM)中)
  • RUNTIME:VM将在运行期也保留注解信息,因此可以通过反射机制读取注解信息(源码、class文件和执行的时候都有注解的信息)

PS:当胡姐未定义Retention值时,默认值是CLASS

代码语言:javascript
复制
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

这表明@Override 注解只在源码阶段存在,javac在编译过程中去掉该注解。

3、@Documented

表示注解会被包含在javaapi文档中 当一个注解被@Documented元注解所修饰时,那么无论在哪里使用这个注解,都会被Javadoc工具文档化。 举例如下

代码语言:javascript
复制
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)public @interface Documented {
}

这个元注解呗@Documented修饰,表示它本身会被文档化。@Retention注解的值RetentionPolicy.RUNTIME表示@Documented这个注解能保留在运行时;@Target元注解的值ElementType.ANNOTATION_TYPE表示@Documented这个注解只能够来修饰注解类型

4、@Inherited

允许子类继承父类的注解。 用于描述某个被标注的类型可被继承的,如果一个使用了@Inherited修饰的annotation类型类型被用于一个class,则这个annotation将被用于该class类的子类。 表明被修饰的注解类型是自动继承的。如果你想让一个类和它的子类都包含某个注解,就可以使用@Inherited来修饰这个注解。也就是说,假设@Parent类是Child类的父类,那么我们若用被@Inherited元注解所修饰的某个注解对Parent类进行了修饰,则相当于Child类也被该注解所修饰了。这个元注解的定义如下:

代码语言:javascript
复制
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)public @interface Inherited {
}
代码语言:javascript
复制
@Inherited
public @interface MyAnnotation {
}

@MyAnnotation
public class MySuperClass {
}

public class MySubClass extends MySuperClass {
}

上述代码的大致意思是使用@Inherited修饰注解MyAnnotation使用MyAnnotation注解MySuperClass实现类MySubclass继承自MySuperClass

当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

三、标准注解/内建注解

Java本身内建了一些注解,用来为编译器提供指令。如下:

  • @Override
  • @Deprecated
  • @SuppressWarnings 下面让我们详细了解下三个标准注解/内建注解
1、@Override注解

@Override注解用来修饰对父类进行重写的方法。如果一个并非重写父类的方法使用这个注解,编译器将提示错误。

实际上在子类中重写父类或接口的方法,@Overrider并不是必须的。但是还是建议使用这个注解,在某些情况下,假设你修改了父类的方法的名字,那么之前重写子类方法将不再属于重写,如果没有@Override,你将不会觉察到这个子类的方法。有了这个注解修饰,编译器则会提示你这些信息。 例子如下:

代码语言:javascript
复制
public class MySuperClass {

    public void doTheThing() {
        System.out.println("Do the thing");
    }
}


public class MySubClass extends MySuperClass{

    @Override
    public void doTheThing() {
        System.out.println("Do it differently");
    }
}
2、@ Deprecated

@Deprecate 标记类、方法、属性,如果上述三种元素不再使用,使用@Deprecated注解,建议用户不再使用

如果代码使用了@Deprecate 注解的类、方法或属性,编译器会进行警告。 举例如下:

代码语言:javascript
复制
@Deprecated
public class MyComponent {
}

当我们使用@Deprecate注解后,建议配合使用对应的@deprecated JavaDoc 符号,并解释说明为什么这个类,方法或属性被弃用,已经替代方案是什么?如下:

代码语言:javascript
复制
@Deprecated
/**
  @deprecated This class is full of bugs. Use MyNewComponent instead.
*/
public class MyComponent {
}
3、@SuppressWarnings

@SuppressWarnings 用来抑制编译器生成警告信息。可以修饰的元素为类,方法,方法参数,属性,局部变量。

使用场景:当我们一个方法调用了弃用的方法或者进行不安全的类型转换,编译器会生成警告。我们可以为这个方法增加@SuppressWarnings 注解,来抑制编译器生成警告。

PS:使用@SuppressWarnings注解,采用就近原则,比如一个方法出现警告,我们尽量使用@SuppressWarnings注解这个方法,而不是注解方法所在的类。虽然两个都能抑制编译器生成警告,但是范围越小越好,因为范围到了,不利于我们发现该类下其他方法的警告信息。 举例如下:

代码语言:javascript
复制
@SuppressWarnings
public void methodWithWarning() {
}

四、自定义注解

1、注解格式

了解完系统注解之后,我们就可以自己定义注解了,通过上面的@Override的实例,不难看出定义注解的格式如下:

代码语言:javascript
复制
public @Interface 注解名{定义体}

PS:定义体就是方法的集合,每个方法实则是生命了一个配置参数,方法的名称作为配置参数的名称,方法的返回值类型就是配置参数的类型,和普通的方法不一样,可以通过default关键字来声明配置参数的默认值。 注意:

  • 1、注解类型是通过"@interface"关键字定义的
  • 2、此处只能使用public或者默认的default两个权限修饰符
  • 3、配置参数的类型只能使用基本类型(byte,boolean,char,short,int,long,float,double和String,Enum,Class,annotation)
  • 4、对于只含有一个配置参数的注解,参数名建议设置中value,即方法名为value.
  • 5、配置参数一旦设置,其参数值必须有确定的值,要不在使用注解的时候指定,要不在定义注解的时候使用default为其设置默认值,对于非基本类型的参数值来说,其不能为null。
2、创建自己的注解

在Java中,我们可以创建自己的注解,注解和类,接口文件一样定义在自己的文件里面。如下:

代码语言:javascript
复制
@interface MyAnnotation {
   String   name();
   int      age();
   String   sex();
 
 
}

上述代码定义了一个叫做MyAnnotation的注解,它有4个元素。再次强调一下,@Interface 这个关键字 用来告诉java编译器这是一个注解。 应用举例

代码语言:javascript
复制
@MyAnnotation(
    name="张三",
    age=18,
    sex="男"
)
public class MyClass {
}

注意,我们需要为所有的注解元素设置值,一个都不能少。

3、自定义注解默认值

对于注解总的元素,我们可以为其设置默认值,使用方法如下:

代码语言:javascript
复制
@interface MyAnnotation {
    String   name();
    int      age();
   String   sex() default "男";
}

上述代码,我们设置了sex元素的默认值为"男"。当我们在使用时,可以不设置sex的值,即让value使用空字符串默认值。举例如下;

代码语言:javascript
复制
@MyAnnotation(
    name="Jakob",
    age=37,
)
public class MyClass {
}

五、注解的原理

1、注解处理器

如果没有用来读取注解的方法和工作,那么注解也就不会比注释更有用户了,使用注解的过程中,很重要的一部分就是创建与使用注解处理器。Java SE 扩展了反射机制的API,以帮助程序员快速的构造自定义注解处理器。

2、注解处理器的分类

我们已经知道了如何自定义注解,当时想要注解发挥实际作用,需要我们为注解编写响应的注解处理器,根据注解的特性,注解处理器可以分为运行时注解处理器编译时注解处理器。运行时注解处理器需要借助反射机制实现,而编译时处理器则需要借助APT来实现。

无论是运行时注解处理器还是编译时注解处理器,主要工作都是读取注解及处理特定主机,从这个角度来看注解处理器还是非常容易理解的。

3、运行时注解处理器

熟悉Java反射机制的同学一定对java.lang.reflect包非常熟悉,该包中的所有API都支持读取运行时Annotation的能力,即属性为@Retention(RetentionPolicy.RUNTIME)的注解。

在Java.lang.reflect中中的AnnotatedElement接口是所有程序元素的(Class、Method)父接口,我们可以通过反射获取到某个类的AnnotatedElement对象,进而可以通过该对象提供的方法访问Annotation信息,常用的方法如下:

方法

含义

< T extends Annotation > T getAnnotation(Class <T> annotationClass)

表示返回该元素上存在的定制类型的注解

Annotation[] getAnnotations()

返回该元素上存在的所有注解

default <T extends Annotation> T[] getAnnotationsByType(Class <T> annotationClass)

返回该元素制定类型的注解

default <T extends Annotation> T getDeclaredAnnotation( Class <T> annotationClass)

返回直接存在与该元素上的所有注解

default <T extends Annotation>T[] getDeclaredAnntationsByType(Class <T> annotationClass)

返回直接存在该元素上某类型的注解

Annotation[] getDeclaredAnnotations()

返回该元素上的所有注解

举例说明 一个User实体类

代码语言:javascript
复制
public class User {
    private int id;
    private int age;
    private String name;

    @UserData(id=1,name="张三",age = 10)
    public User() {
    }
    public User(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
  //...省略setter和getter方法
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

我们希望可以通过@UserData(id=1,name="张三",age = 10)这个注解,来为设置User实例的默认值。 自定义注解如下:

代码语言:javascript
复制
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.CONSTRUCTOR)
public @interface UserData {
    public int id() default 0;
    public String name() default "";
    public int age() default 0;
}

该注解类作用于构造方法,并在运行时存在,这样我们就可以在运行时通过反射获取注解进而为User实例设值,看看如何处理该注解 运行时注解处理器:

代码语言:javascript
复制
public class AnnotationProcessor {

    public static void init(Object object) {

        if (!(object instanceof User)) {
            throw new IllegalArgumentException("[" + object.getClass().getSimpleName() + "] isn't type of User");
        }

        Constructor[] constructors = object.getClass().getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            if (constructor.isAnnotationPresent(UserMeta.class)) {
                UserMeta userFill = (UserMeta) constructor.getAnnotation(UserMeta.class);
                int age = userFill.age();
                int id = userFill.id();
                String name = userFill.name();
                ((User) object).setAge(age);
                ((User) object).setId(id);
                ((User) object).setName(name);
            }
        }
    }
}

测试代码

代码语言:javascript
复制
public class Main {

    public static void main(String[] args) {
        User user = new User();
        AnnotationProcessor.init(user);
        System.out.println(user.toString());
    }
}

运行测试代码,便得到我们想要的结果:

代码语言:javascript
复制
User{id=1, age=10, name=’dong’}

这里通过反射获取User类声明的构造方法,并检测是否使用了@UserData注解。然后从注解中获取参数值并将其复赋值给User对象。 正如上面所说,运行时注解处理器的编写本质上就是通过反射获取注解信息,随后进行其他操作。编译一个运行时注解处理器就是那么简答。运行时注解通常多用于参数配置模块。

4、编译时注解处理器

不同于运行时注解处理器,编写编译时注解处理器(Annotation Processor Tool)。 APT 用于编译时期扫描和处理注解信息,一个特定的注解处理器可以以Java源文件或编译后的class文件作为输入,然后输出另一些文件,而已是.java文件,也可以是.class文件,但通常我们输出的是.java文件。(注意:并不是对源文件进行修改),这些java文件会和其他源文件一起被javac编译。 你可能会很纳闷,注解处理器是到底在什么阶段介入的呢?好吧,其实是在javac开始编译之前,这就是通常我们为什么愿意输出.java文件的原因。

注解最早是在java 5引入的,主要包含APT和com.sum.mirror包中现相关mirror api,此时APT和javac是各自独立的,但是从Java 6开始,注解处理器正式标准化,APT工具也被直接集成在javac当中。

编译时注解处理器编译一个注解时,主要分2步

  • 1、 继承AbstractProcessor,实现自己的注解处理器
  • 2、注册处理器,并打包成jar

举例说明: 首先来看一下一个标准的注解处理器的格式:

代码语言:javascript
复制
public class MyAnnotationProcessor extends AbstractProcessor {

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return super.getSupportedAnnotationTypes();
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return super.getSupportedSourceVersion();
    }

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        return false;
    }
}

来简单的了解下其中5个方法的作用

方法

作用

init(ProcessingEnvironment processingEnv)

该方法有注解处理器自动调用,其中ProcessingEnvironment类提供了很多有用的工具类:Filter,Types,Elements,Messager等

getSupportedAnnotationTypes()

该方法返回字符串的集合表示该处理器用于处理那些注解

getSupportedSourceVersion()

该方法用来指定支持的Java版本,一般来说我们都是支持到最新版本,因此直接返回SourceVersion.latestSupported()即可

process(Set annotations, RoundEnvironment roundEnv)

该方法是注解处理器处理注解的主要地方,我们需要在这里写扫描和处理注解的代码,以及最终生成的java文件。其中需要深入的是RoundEnvironment类,该用于查找出程序元素上使用的注解

编写一个注解处理器首先要对ProcessingEnvironment和RoundEnvironment非常熟悉。接下来我们来了解下这两个类,先看下ProcessingEnvironment类:

代码语言:javascript
复制
public interface ProcessingEnvironment {

    Map<String,String> getOptions();

    //Messager用来报告错误,警告和其他提示信息
    Messager getMessager();

    //Filter用来创建新的源文件,class文件以及辅助文件
    Filer getFiler();

    //Elements中包含用于操作Element的工具方法
    Elements getElementUtils();

     //Types中包含用于操作TypeMirror的工具方法
    Types getTypeUtils();

    SourceVersion getSourceVersion();

    Locale getLocale();
}

重点来认识一下Element,Types和Filer。Element(元素)是什么呢?

Element

element表示一个静态的,语言级别的构件。而任何一个结构化文档都可以看作是由不同的element组成的结构体,比如XML,JSON等。这里我们用XML来示例:

代码语言:javascript
复制
<root>
  <child>
    <subchild>.....</subchild>
  </child>
</root>

这段xml中包含了三个元素:<root>、<child>、<subchild>到现在你已经明白元素是什么。对java源文件来说,他同样是一种结构化文档:

代码语言:javascript
复制
package com.demo;             //PackageElement
public class Main{                  //TypeElement
    private int x;                  //VariableElement
    private Main(){                 //ExecuteableElement
    }
    private void print(String msg){ //其中的参数部分String msg TypeElement
    }
}

对于java源文件来说,Element代表程序元素:包,类,方法都是一种程序元素。另外如果你对网页解析工具jsoup熟悉,你会觉得操作此处的element是非常容易,关于jsoup不在本文讲解之内。

接下来看看各种Element之间的关系图,以便有个大概的了解

element关系图.png

元素

含义

VariableElement

代表一个 字段, 枚举常量, 方法或者构造方法的参数, 局部变量及 异常参数等元素

PackageElement

代表包元素

TypeElement

代表类或接口元素

ExecutableElement

代码方法,构造函数,类或接口的初始化代码块等元素,也包括注解类型元

TypeMirror、TypeElement、DeclaredType 这三个类我也简单的介绍下:

  • TypeMirror:代表Java语言中类型.Types包括基本类型,声明类型,数组,类型变量和空类型。也代表通配类型参数,可执行文件的签名和返回类型等.
  • TypeElement 代表类或接口元素
  • DeclaredType 代表类型或接口类型

简单的来说,Element代表源代码,TypeElement代表的是源码中的类型元素,比如类,虽然我们可以从TypeElement中获取类名,TypeElement中不包含类本身的信息,比如它的父类,要想获取这信息需要借助TypeMirror,可以通过的Element中的asType()获取元素对应的TypeMirror。

Filer

Filter 用于注解处理器中创新文件。

然后看一下RoundEnvironment这个类,这个类比较简单

代码语言:javascript
复制
public interface RoundEnvironment {

    boolean processingOver();

     //上一轮注解处理器是否产生错误
    boolean errorRaised();

     //返回上一轮注解处理器生成的根元素
    Set<? extends Element> getRootElements();

   //返回包含指定注解类型的元素的集合
    Set<? extends Element> getElementsAnnotatedWith(TypeElement a);

    //返回包含指定注解类型的元素的集合
    Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a);
}

然后来看一下RoundEnvironment,这个类比较简单,一笔带过: public interface RoundEnvironment { boolean processingOver(); //上一轮注解处理器是否产生错误 boolean errorRaised(); //返回上一轮注解处理器生成的根元素 Set<? extends Element> getRootElements(); //返回包含指定注解类型的元素的集合 Set<? extends Element> getElementsAnnotatedWith(TypeElement a); //返回包含指定注解类型的元素的集合 Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a);}

Filer Filer用于注解处理器中创建新文件。具体用法在下面示例会做演示.另外由于Filer用起来实在比较麻烦,后面我们会使用javapoet简化我们的操作. 好了,关于AbstractProcessor中一些重要的知识点我们已经看完了.假设你现在已经编写完一个注解处理器了,下面,要做什么呢? |

打包并注册.

自定义的处理器如何才能生效那?为了让Java编译器找到自定义的注解处理器我们需要对其进行注册和打包:自定义的处理器需要被达成一个jar,并且需要在jar包的META-INF/services路径下中创建一个固定的文件 javax.annotation.processing.processor,在javax.annotation.processing.Processor文件中需要填写自定义处理器的完整路径名,有几个处理器就要填写几个 从Java 6之后,我们只需要将打开的jar防止到项目的buildpath下即可,javac在运行的过程会自动检查javax.annotation.processing.Processor注册的注解处理器,并将其注册上。而Java 5需要单独使用APT工具。 最终我们需要获得一个包含注解处理器的代码的jar包

六、注解基础知识思维导图

最后借用下别人的Java注解的基础知识点导图

Java注解.png

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.06.27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、Java注解技术基本概念
    • (一) 什么是注解
      • (二) 什么是元数据(metadata)
        • (三) 注解的前世今生
          • (四)为什么要使用注解
            • (五)、注解的作用
              • (六) 注解基础
                • (七) 注解元素
                  • (八)注解使用
                  • 二、元注解
                    • (一) 什么是元注解
                      • 4、@Inherited
                      • 三、标准注解/内建注解
                        • 1、@Override注解
                          • 2、@ Deprecated
                            • 3、@SuppressWarnings
                            • 四、自定义注解
                              • 2、创建自己的注解
                                • 3、自定义注解默认值
                                • 五、注解的原理
                                  • 1、注解处理器
                                    • 2、注解处理器的分类
                                      • 3、运行时注解处理器
                                        • 4、编译时注解处理器
                                        • 六、注解基础知识思维导图
                                        相关产品与服务
                                        腾讯云代码分析
                                        腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
                                        领券
                                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档