注解和注解处理器
来源:互联网 发布:游戏原画网络班 编辑:程序博客网 时间:2024/05/29 07:49
注解机制 = 注解 + 注解处理器
注解定义规则, 注解处理器实现规则定义的处理.
注解
注解是一种语言. 其使用的符号系统如下:
使用语法
@Annotation@Annotation2(Element1 [, Element2]) // Element: name = valueClass/Method/Field
- 注解标记于 @Target 元注解指定的语言结构上方(见下文元注解)
- 注解可指定元素, 元素为名值对, 元素被注解处理器使用; 特殊地, 没有元素的注解称为标记注解
定义语法
@Meta Annotationpublic @interface ANNOTATION_NAME { // 元素定义(可选) public ANNOTATION_DATA_TYPE ELEMENT_NAME() [default DEFAULT_VALUE];}
- 注解定义语法和接口类似, 但用 @interface 保留字
- 注解元素定义语法和方法类似, 但可指定默认值
- 注解元素可用类型包括
- 基本数据类型(不允许使用包装类型)
- String
- 枚举类型
- Class
- 注解类型
- 以上类型的数据类型
- 注解需要用元注解描述
元素值和注解元素默认值不能为 null, (惯例)通常使用负数或空字符串表示某个元素不存在.
元注解专用于定义注解, Java 提供了四种:
- @Target 定义注解目标, 可以注解的目标定义在 ElementType 枚举中, 包括
- PACKAGE 包声明
- TYPE 类、接口、枚举声明
- CONSTRUCTOR 构造器声明
- FIELD 字段声明
- METHOD 方法声明
- PARMETER 参数声明
- LOCAL_VARIABLE 局部变量声明
- @Retention 定义注解在哪些阶段是有效的, 阶段定义在 RetentionPolicy 枚举中, 包括
- SOURCE 编译时无效
- CLASS 编译时有效
- RUNTIME 编译时和运行时都有效
- @Documented 指定该注解将包含在 Javadoc 中
- @Inherited 允许子类继承父类中的注解
说明
- 解释@Inherited注解: 子类继承父类, 且父类被注解, 若注解子类的注解定义中包含 @Inherited, 则子类也继承父类的注解
- @Target 注解值
- 没有 @Target: 表示该注解可用于注解 ElementType 中定义的任意元素
- @Target 单个值, 如 @Target(ElementType.TYPE): 表示该注解仅用于注解特定的目标, 比如这里仅用于注解类型
- @Target 多个值, 如 @Target(ElementType.TYPE, ElementType.FIELD): 表示该注解能注解指定范围的目标, 比如这里可注解类型和字段
预定义的注解
Java 内置了3个功能性注解和4个元注解(介绍见上文), 3个功能性注解:
- @Override 告诉编译器“我想重写方法”
- @Deprecated 告诉编译器”告知使用者该目标过时”
- @SuppressWarnings 告诉编译器”你给出的警告不恰当, 关闭警告”
注解处理器
注解处理器可以在编译器进行注解处理, 可以在运行时通过反射API进行注解处理.
注解处理器在 Java 5 引入, 但那时并没有标准化的 API 可用, 需通过 apt(Annotation Processing Tool)结合 Mirror API(com.sun.mirror)来实现. Java 6 开始, 注解处理器被标准化, 定义在 JSR 269 标准中, 在标准库中提供了 API, apt 被集成到 javac 工具.
编译时 Java 6 注解处理器
了解注解处理器 API
注解处理器的 API 定义在javax.annotation.processing
包中, 其中 Processor 接口定义注解处理器, 子类 AbstractorProcessor 抽象类额外添加了便捷方法.
- Processor 的实现类必须要有一个无参构造器
- void init(ProcessingEnvironment processingEnv) 注解处理器初始化, 被调用的过程中传入的 ProcessingEnvironment 中包含了许多工具类:
- boolean process(Set, RoundEnvironment) 注解处理方法, 定义注解处理
- Java 编译器每遇到一个被 @SupportedAnnotationType 指定注解注解的类, 就调用一次 process
- Set 当前注解处理器要处理的注解类型
- RoundEnvironment 上一次注解处理中处理的源文件
注解处理器通过下面三个注解来进行配置:
- @SupportedAnnotationType 指定注解处理器处理的注解类型, 该注解的元素为 String[] value, 需要传入注解类型全限定名, 也支持通配符
- @SupportedSourceVersion 指定注解处理器处理的源代码版本, 该注解的元素为 SourceVersion value, 可选值定义在
javax.lang.model.SourceVersion
枚举类中 - @SupportedOperation 指定注解处理器可以接收的命令行参数选项, 该注解的元素为 String[] value
定义注解
package gf.annotation;public @interface Complexity { public enum Level { VERY_SIMEPLE, SIMPLE, MEDIUM, COMPLEX, VERY_COMPLEX } default @Complexity.MEDIUM}
注解类
pakcage gf.annotation;@Complexity(ComplexityLevel.VERY_SIMPLE)public class SimpleAnnotationTest { @Complexity() public void method() { System.out.println("console"); }}
定义
@SupportedAnnotationTypes("gf.annotation.Complexity")@SupportedSourceVersion(SourceVersion.RELEASE_6)public class ComplexityProcessor exntends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { for(Element elem: roundEnv.getElementsAnnotatedWith(Complexity.class)) { Complexity complexity = elem.getAnnotation(Complexity.class); String message = "annotated with: " + elem.getSimpleName(); } return true; }}
打包和注册
将注解处理器打包为 .jar 包, 需要在其中定义的 META-INF/services 目录下定义一个 javax.annotaiton.processing.Processor 文件, 内容为注解处理器的全限定名, 每行一个.
运行
将注解和注解处理器加入到 javac 的环境变量并进行注解处理
javac - cp MY_ANNOTATION.jar;MY_ANNOTATION_PROCESSOR.jar 被注解的源文件比如 javac -cp sdc.assets.annotations-1.0-SNAPSHOT.jar; sdc.assets.annotations.processors-1.0-SNAPSHOT.jar SimpleAnnotationsTest.java
Eclipse 对注解处理器的支持
项目右键 | Properties | Java Compiler | Annotation Processing 开启注解处理器 | Factory Path 指定包含注解处理器的 .jar 包位置, 每次项目构建时自动执行注解处理器。
Annotation Processing 界面配置注解处理器选项
- 生成的源码目录, 默认位于项目根目录下的
.apt_generated
- 处理器选项
Factory Path 界面指定使用的注解处理器的 .jar 包位置
关于注解的一些思考
(似乎什么是xx的问题本身就包含很多问题, xx的所有表现/存在共同定义了xx是什么. 然后从不同角度看待, 就会有不同的描述. 一个事物的没有绝对的意义, 需要通过外界来定义其自身. 所以在对xx进行定义时, 要明确其上下文和环境.)
注解是一种语言特性, 是一种解决方案. 每个解答都来自一个问题. 那么“问题1:是什么原因(原因是一个问题/不便)导致人们需要注解这样一种机制?”.
因为人们有着潜在的需要, “更好更快更方便…”. 在进行某个活动的过程中, 逐渐感受和意识到其中产生问题的地方和带来不便的地方. 进而就有想要改进的欲望. 而解决问题就是研究背后的原理和规律, 找出导致不便(”症状”)的原因(”病因”). 进而从量上进行改变, 增加或减少.
// 具体原因待查
总之, 要解决问题需要熟悉机理找出背后的原因, 促进某些因素, 抑制某些因素.
我们将注解定义为一种“更完善的描述程序的机制”, 那么“问题2:怎样理解‘完整’呢? ”
我认为, 通常先有了问题, 然后提出解决方案. 通常, 解决方案又促进了认识, 从而提出‘有了注解的程序才是完整的’. 也就是说在问题被解决前, 人们并不知道当时程序的描述是并不完整的. 实际上, 现在即使有了注解就一定能说我们现在对程序的描述是完整的了吗? 并不然, 只能相对没有注解之前而言, 是更加完整了. 现在如果有了新的需求/问题, 在解决方案提出之后, 我们可能又发现现在的有了注解的描述也可能是不完整的. 这就是计算机技术的发展规律, 在解决问题的过程中, 更好的方法被提出; 同时问题也在发生着改变. 这是一个不停演进的过程. “
也就是说, 事物是发展变化的, 完整是相对的. 解决方案也会使问题改变, 果和因也是相对的.
“问题3:现在我们是如何衡量其完整性的/什么样的描述对程序而言是完整的?”
// 待考究
一些认识
注解并不是Java编程语言的一部分. (正确. 在 Java SE 5 前是这样的)
注解是 Java 编程语言的一部分. (正确. 从 Java SE 5 开始是这样的)
注解这种机制是一种与 Java 编程语言无关的独立存在. (因为在 Java 引入该机制前它就存在了)
注解是一种让语言更好的存在, 而不是语言必须的部分. (因为在 Java 引入该机制前就能解决问题)
参考
- 《Java 编程思想(第4版)》
- Java 注解处理器
- 使用注解处理器生成代码 - 2 注解处理器
- 注解和注解处理器
- 注解和注解处理器 Part 2
- Java注解和注解处理器使用详解
- 注解处理器
- 注解(Annotation)注解处理器
- Java注解annotation用法和自定义注解处理器
- Java注解annotation用法和自定义注解处理器
- Java注解annotation用法和自定义注解处理器
- Java注解annotation用法和自定义注解处理器
- SpringMVC_非注解(注解)的处理器映射器和适配器
- 非注解和注解的处理器映射器、适配器配置
- Java注解annotation用法和自定义注解处理器
- 注解(Annotation)--注解处理器
- 注解三之注解处理器
- 注解(Annotation)--注解处理器
- 注解(Annotation)--注解处理器
- Java注解(二):注解处理器
- 注解的处理器映射器和适配器
- AngularJS进阶(三十六)AngularJS项目开发技巧之利用Service&Promise&Resolve解决图片预加载问题(后记)
- php面试常用知识点总结
- Android动态加载一
- Celery任务调度示例
- ShareSDK无法微信分享以及登录的解决方法
- 注解和注解处理器
- LeetCode Binary Tree Inorder Traversal
- Linux系统运维——0
- Android事件分发详细介绍
- POJ2686 状态压缩dp
- 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 (HDU_2191) 多重背包 + 二进制思想优化
- 打造统一第三方SDK接入框架(用户模块,支付模块,发享模块)(一)
- 11.2 Job Seperation causes WARNINGS and ORA-15025 ORA-27041 With Certain Users (文档 ID 1317692.1)
- 对jsp九大内置对象的理解