Java进阶_3 注解、APT

一、注解的概念

注解(Annotation)

​ 也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

三种标准注解

  • @Override

    用于重写父类方法,或者实现接口对应的方法

  • @Deprecated

    用于申明函数,变量,类等过时,后续的版本中可能会被删除,不推荐使用,申明了该注解的对象会被打上破折号

  • @SuppressWarnings

    注解元素上的编译器警告应该被压制. 在类上的压制会同样作用到类的方法上.

四种元注解

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

  • @Target

    该标识用于描述注解的使用范围(即:被描述的注解可以用在什么地方): packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

    取值(ElementType)有:
      1.CONSTRUCTOR:用于描述构造器
      2.FIELD:用于描述域
      3.LOCAL_VARIABLE:用于描述局部变量
      4.METHOD:用于描述方法
      5.PACKAGE:用于描述包
      6.PARAMETER:用于描述参数
      7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

  • @Retention

    该标示定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。

    取值(ElementType)有:
     1.SOURCE:在源文件中有效(即源文件保留)
     2.CLASS:在class文件中有效(即class保留)
     3.RUNTIME:在运行时有效(即运行时保留)

  • @Documented

    Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员

  • @Inherited

    @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

    注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

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

自定义注解

  • 格式:

    注解
    public @interface 注解名 {定义体}
    

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。

注解参数的可支持数据类型:

​ 1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
​ 2.String类型
​ 3.Class类型
​ 4.enum类型
​ 5.Annotation类型
​ 6.以上所有类型的数组

Annotation类型里面的参数设定:

1.只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型; 
2.参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;  
 3.如果只有一个参数成员,最好把参数名称设为”value”,后加小括号.例:下面的例子FruitName注解就只有一个参数成员。

下面是一个简单的自定义注解的栗子:

package annotation;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 动物名称注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AnimalName {String value();
}

​ 定义了注解,并在需要的时候给相关类,类属性加上注解信息,如果没有响应的注解信息处理流程,注解可以说是没有实用价值,接下来要介绍的是java的APT(Annotation Process Tool)技术,用于处理自定义注解。

APT技术

概念

APT即为Annotation Processing Tool,它是javac的一个工具,中文意思为编译时注解处理器。APT可以用来在编译时扫描和处理注解。通过APT可以获取到注解和被注解对象的相关信息,在拿到这些信息后我们可以根据需求来自动的生成一些代码,省去了手动编写。注意,获取注解及生成代码都是在代码编译时候完成的,相比反射在运行时处理注解大大提高了程序性能。APT的核心是AbstractProcessor类。

构建APT项目

  1. 首先,新建一个Android项目,然后File–>New–>New Module,打开如上图所示的面板,选择Java Library即可。一个APT项目至少应该由两个Java Library模块:

    • 首先需要一个Annotation模块,这个用来存放自定义的注解。
    • 另外需要一个Compiler模块,这个模块依赖Annotation模块。
  2. 项目的App模块和其它的业务模块都需要依赖Annotation模块,同时需要通过annotationProcessor依赖Compiler模块。
    app模块的gradle中依赖关系如下:

    implementation project(':annotation')
    annotationProcessor project(':factory-compiler')
    

图1-APT项目模块结构图

为什么要强调上述两个模块一定要是Java Library?如果创建Android Library模块你会发现不能找到AbstractProcessor这个类,这是因为Android平台是基于OpenJDK的,而OpenJDK中不包含APT的相关代码。因此,在使用APT时,必须在Java Library中进行。

  • annotation模块自定义注解

    @Target({ElementType.TYPE})   \\作用范围 Class@Retention(RetentionPolicy.CLASS)  \\生命周期:仅保留到.class文件public @interface Route {/** Path of route*/String value();  //类似于成员变量
    }
    
  • compiler模块实现自己的注解处理器

    public class RouteProcessor extends AbstractProcessor {@Overridepublic synchronized void init(ProcessingEnvironment env){ // 主要做一些初始化操作}@Overridepublic Set<String> getSupportedAnnotationTypes() { // 支持处理的注解类型, 在这里就是@Route}@Overridepublic boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { //具体处理注解的逻辑,控制代码的生成processAnnotations();}@Overridepublic SourceVersion getSupportedSourceVersion() {//java版本 如:jdk1.6or jdk1.7}}
    

    (1) public SourceVersion getSupportedSourceVersion()
    这个方法非常简单,只有一个返回值,用来指定当前正在使用的Java版本,通常return SourceVersion.latestSupported()即可。

    (2) public Set getSupportedAnnotationTypes()
    这个方法的返回值是一个Set集合,集合中指要处理的注解类型的名称(这里必须是完整的包名+类名,例如Route.class.getCanonicalName())。由于在本例中只需要处理@Route注解,因此Set集合中只需要添加@Route的名称即可。

    (3) public synchronized void init(ProcessingEnvironment processingEnvironment)
    这个方法用于初始化处理器,方法中有一个ProcessingEnvironment类型的参数,ProcessingEnvironment是一个注解处理工具的集合。它包含了众多工具类。例如:

    • Filer可以用来编写新文件;
    • Messager可以用来打印错误信息;
    • Elements是一个可以处理Element的工具类。

    在Java语言中,Element是一个接口,表示一个程序元素,它可以指代包、类、方法或者一个变量。Element已知的子接口有如下几种:

    • PackageElement 表示一个包程序元素。提供对有关包及其成员的信息的访问。

      • ExecutableElement 表示某个类或接口的方法、构造方法或初始化程序(静态或实例),包括注释类型元素。
      • TypeElement 表示一个类或接口程序元素。提供对有关类型及其成员的信息的访问。注意,枚举类型是一种类,而注解类型是一种接口。
      • VariableElement 表示一个字段、enum 常量、方法或构造方法参数、局部变量或异常参数。

    把Java类看作一个类似XML或者JSON一样的东西。有了这个概念之后我们就可以很容易的理解什么是Element了。带着这个概念来看下面的代码:

    package com.annotation.factory;  //    PackageElementpublic class Circle {  //  TypeElementprivate int i; //   VariableElementprivate Triangle triangle;  //  VariableElementpublic Circle() {} //    ExecuteableElementpublic void draw(   //  ExecuteableElementString s)   //  VariableElement{System.out.println(s);}@Overridepublic void draw() {    //  ExecuteableElementSystem.out.println("Draw a circle");}
    }
    

    不同类型Element其实就是映射了Java中不同的类元素。

    (4) public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment)
    FactoryProcessor是最重要的一个方法了。先看这个方法的返回值,是一个boolean类型,返回值表示注解是否由当前Processor 处理。如果返回 true,则这些注解由此注解来处理,后续其它的 Processor 无需再处理它们;如果返回 false,则这些注解未在此Processor中处理并,那么后续 Processor 可以继续处理它们。
    在这个方法的方法体中,我们可以校验被注解的对象是否合法、可以编写处理注解的代码,以及自动生成需要的java文件等。因此说这个方法是AbstractProcessor 中的最重要的一个方法。我们要处理的大部分逻辑都是在这个方法中完成。

  • 在AS中使用注解

    @Route(path = "/test/activity2")
    public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_test2);}
    }
    

参考:

(6条消息) java注解与APT技术_fengxingzhe001的专栏-CSDN博客

(6条消息) Java进阶–编译时注解处理器(APT)详解_smily的博客-CSDN博客

Java进阶_3 注解、APT相关推荐

  1. java进阶之注解篇

    文章目录 注解 基本语法 定义注解 元注解 编写注解处理器 注解元素 默认值限制 生成外部文件 替代方案 注解不支持继承 实现处理器 注解 注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化 ...

  2. Java、Android注解代码生成(ButterKnife原理、ViewBinding)

    前言 首先需要一些先验知识: 浅谈Java/Android下的注解 Java.Android基础之-反射 Java.Android静态代理与动态代理 简介 在我们常用的框架中注解和自动生成代码的身影很 ...

  3. Java进阶(五)Java I/O模型从BIO到NIO和Reactor模式

    本文介绍了Java中的四种I/O模型,同步阻塞,同步非阻塞,多路复用,异步阻塞.同时将NIO和BIO进行了对比,并详细分析了基于NIO的Reactor模式,包括经典单线程模型以及多线程模式和多Reac ...

  4. java annotation list_Java 注解 (Annotation)你可以这样学

    注解语法 因为平常开发少见,相信有不少的人员会认为注解的地位不高.其实同 classs 和 interface 一样,注解也属于一种类型.它是在 Java SE 5.0 版本中开始引入的概念. 注解的 ...

  5. 深入理解JAVA中的注解

    本文来说下JAVA中的注解,这个技术虽然我们每天都在使用,但是不一定知道其实现原理.本文来详细介绍下JAVA中注解相关的知识. 文章目录 概述 什么是注解 注解的本质是什么 注解体系图 常用元注解 @ ...

  6. java编译时注解_简单介绍 Java 中的编译时注解

    1. 前言 上一篇 主要介绍了什么是 注解 (Annotation) 以及如何读取 运行时注解 中的数据, 同时用注解实现了简单的 ORM 功能. 这次介绍另一部分: 如何读取 编译时注解 ( Ret ...

  7. Java语言使用注解处理器生成代码——第二部分:注解处理器

    原文作者:deors 原文地址:https://deors.wordpress.com/2011/10/08/annotation-processors/ 译文作者:Jianan - qinxiand ...

  8. 视频教程-Java进阶高手课-Spring精讲精练-Java

    [ [这里是图片001] Java进阶高手课-Spring精讲精练 中国科学技术大学硕士研究生,丹麦奥尔堡大学访问学者,先后就职于eBay.蚂蚁金服.SAP等国内外一线互联网公司,在Java后端开发. ...

  9. Java基础到Java进阶——Java小白的历练之路------从0到1,开卷!

    Java小白的历练之路------从0到1 title: Java Essay date: 2022-09-07 08:58:32 tags: Java notes 写在前面: 免责声明:本笔记来源自 ...

最新文章

  1. 解决 vue路由跳转到新页面底部而不是顶部和后退到首页就不让他继续后退了
  2. mysql监控sql_关于对mysql语句进行监控的方法详解
  3. VMware虚拟机中ubuntu的磁盘怎么扩容
  4. 面试准备每日五题:C++(八)——重写重载隐藏、vector相关
  5. Spring Boot : Whitelabel Error Page解决方案
  6. utorrent设置上传速度_utorrent下载速度很慢怎么设置?
  7. java构造函数注释_@Autowired的使用:推荐对构造函数进行注释
  8. 基于SSM框架的志愿者管理系统
  9. python编写视频播放器_python十几行代码实现简单播放器
  10. 腾讯微信短网址(url.cn)在线生成接口API使用详解
  11. Consul小贴士-记一次Consul注册failing状态跟踪
  12. TDengine 在IT运维监控领域的应用
  13. 多进程爬取补天的厂商
  14. 你知道数据分析报告应该如何写吗?
  15. android系统最近删除照片,安卓手机最近删除的照片怎么恢复?专家教你这样做...
  16. 图片怎么自定义裁剪?图片如何裁出想要的大小?
  17. 测试方法——因果图法和判定表法
  18. PHP解析js的escape()函数编码数据
  19. 5G移动性增强技术分析
  20. 服务器向虚拟机迁移,windows物理机服务器迁移到虚拟机

热门文章

  1. 基础计算机教学论文,基础计算机论文,关于民办院校计算机基础课程实践教学体会相关参考文献资料-免费论文范文...
  2. 教育孩子,是从小的润雨细无声。纯属个人文学闷骚型。。。
  3. 出了山寨机,国产的就没法活了?
  4. 2021-01-27 大数据课程笔记 day7
  5. 项目管理实战精髓培训课
  6. 如何高效制作数据可视化大屏,大屏高效制作攻略分享,总有一款适合你
  7. 无法启动计算机的杀毒软件,电脑中毒杀毒软件无法启动任务管理器也被禁用怎么办?...
  8. 回文日期 php,c语言程序实例大全,220个详细程序源代码
  9. 从星图地球数据云看塔克拉玛干沙漠
  10. MSI和MSI-X对比(五)