Java 注解基本原理
注解的本质
「java.lang.annotation.Annotation」接口中有这么一句话,用来描述『注解』。
The common interface extended by all annotation types
所有的注解类型都继承自这个普通的接口(Annotation)
这句话有点抽象,但却说出了注解的本质。我们看一个 JDK 内置注解的定义:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
这是注解 @Override 的定义,其实它本质上就是:
public interface Override extends Annotation{
}
没错,注解的本质就是一个继承了 Annotation 接口的接口。有关这一点,你可以去反编译任意一个注解类,你会得到结果的。
一个注解准确意义上来说,只不过是一种特殊的注释而已,如果没有解析它的代码,它可能连注释都不如。
解析一个类或者方法的注解往往有两种形式,一种是编译期直接的扫描,一种是运行期反射。
元注解
『元注解』是用于修饰注解的注解,通常用在注解的定义上。
JAVA 中有以下几个『元注解』:
- @Target:注解的作用目标
- @Retention:注解的生命周期
- @Documented:注解是否应当被包含在 JavaDoc 文档中
- @Inherited:是否允许子类继承该注解
@Target
@Target
注解指明该注解可以作用哪些对象上。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
注解接收一个ElementType数组,ElementType是一个枚举,成员如下:
- ElementType.TYPE:允许被修饰的注解作用在类、接口和枚举上
- ElementType.FIELD:允许作用在属性字段上
- ElementType.METHOD:允许作用在方法上
- ElementType.PARAMETER:允许作用在方法参数上
- ElementType.CONSTRUCTOR:允许作用在构造器上
- ElementType.LOCAL_VARIABLE:允许作用在本地局部变量上
- ElementType.ANNOTATION_TYPE:允许作用在注解上
- ElementType.PACKAGE:允许作用在包上
- ElementType.TYPE_PARAMETER:允许作用在类型参数上
- ElementType.TYPE_USE:允许作用在类型上
@Retention
@Retention 用于指明当前注解的生命周期
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
注解接收一个RetentionPolicy数据,RetentionPolicy是个枚举,成员如下:
- RetentionPolicy.SOURCE:当前注解编译期可见,不会写入 class 文件
- RetentionPolicy.CLASS:类加载阶段丢弃,会写入 class 文件
- RetentionPolicy.RUNTIME:永久保存,可以反射获取
JAVA 的内置三大注解
- @Override
- @Deprecated 标识类或方法不再推荐使用
- @SuppressWarnings 主要用来压制 java 的警告
实现一个自己的注解
定义一个注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HelloAnnotation {
String value() default "Hello annotation!";
}
使用这个注解:
public class UseAnnotation {
@HelloAnnotation
public void hello() {
System.out.println("hello");
}
@HelloAnnotation("Hello world!")
public void helloWorld() {
System.out.println("Hello world!");
}
}
注解最重要的部分在于对注解的处理。注解处理器就是通过反射机制获取被检查方法上的注解信息,然后根据注解元素的值进行特定的处理。如果没有注解处理器,注解就是个注释,或者连注释都不如。
处理这个注解:
public class Test {
public static void main(String[] args) {
testAnnotation(UseAnnotation.class);
}
private static void testAnnotation(Class<?> cl) {
for (Method m : cl.getDeclaredMethods()) {
HelloAnnotation ha = m.getAnnotation(HelloAnnotation.class);
if (ha != null) {
System.out.println("Found My Annotation: " + ha.value());
}
}
}
}
输出结果:
Found My Annotation: Hello annotation!
Found My Annotation: Hello world!
参考资料
原文首发在我的简书 [https://www.jianshu.com/p/c342606e255d](https://www.jianshu.com/p/c342606e255d
Java 注解基本原理的更多相关文章
- Java注解基本原理
注解目前非常的流行,很多主流框架都支持注解,而且自己编写代码的时候也会尽量的去用注解,一时方便,而是代码更加简洁. 注解的语法比较简单,除了@符号的使用之外,它基本与Java固有语法一致.Java S ...
- java 注解 基本原理 编程实现
摘要: java 1.5开始引入了注解和反射,正确的来说注解是反射的一部分,没有反射,注解无法正常使用,但离开注解,反射依旧可以使用,因此来说,反射的定义应该包含注解才合理一些. java 1.5开始 ...
- 10分钟学会JAVA注解(annotation)
(原) 先认识注解(Annotation) 定义类用class,定义接口用interface,定义注解用@interface 如public @interface AnnotationTest{} 所 ...
- Java注解
Java注解其实是代码里的特殊标记,使用其他工具可以对其进行处理.注解是一种元数据,起到了描述.配置的作用,生成文档,所有的注解都隐式地扩展自java.lang.annotation.Annotati ...
- 19.Java 注解
19.Java注解 1.Java内置注解----注解代码 @Deprecated //不推荐使用的过时方法 @Deprecated ...
- Java注解入门
注解的分类 按运行机制分: 源码注解:只在源码中存在,编译后不存在 编译时注解:源码和编译后的class文件都存在(如@Override,@Deprecated,@SuppressWarnin ...
- java注解(Annotation)解析
注解(Annotation)在java中应用非常广泛.它既能帮助我们在编码中减少错误,(比如最常见的Override注解),还可以帮助我们减少各种xml文件的配置,比如定义AOP切面用@AspectJ ...
- JAVA 注解的几大作用及使用方法详解
JAVA 注解的几大作用及使用方法详解 (2013-01-22 15:13:04) 转载▼ 标签: java 注解 杂谈 分类: Java java 注解,从名字上看是注释,解释.但功能却不仅仅是注释 ...
- attilax.java 注解的本质and 使用最佳实践(3)O7
attilax.java 注解的本质and 使用最佳实践(3)O7 1. 定义pojo 1 2. 建立注解By eclipse tps 1 3. 注解参数的可支持数据类型: 2 4. 注解处理器 2 ...
随机推荐
- Can总线上的电平及物理层仲裁
CAN总线采用差分信号传输,通常情况下只需要两根信号线(CAN-H和CAN-L)就可以进行正常的通信.在干扰比较强的场合,还需要用到屏蔽地即CAN-G(主要功能是屏蔽干扰信号),CAN协议推荐用户使用 ...
- Increasing Performance by Reducing Dynamic Dispatch
https://developer.apple.com/swift/blog/?id=39 Increasing Performance by Reducing Dynamic Dispatch Li ...
- Generative Adversarial Networks overview(1)
Libo1575899134@outlook.com Libo (原创文章,转发请注明作者) 本文章会先从Gan的简单应用示例讲起,从三个方面问题以及解决思路覆盖25篇GAN论文,第二个大部分会进一步 ...
- windows cmd命令查看端口占用进程
netstat –ano|findstr [指定端口号] 通过任务管理器杀死相关的进程 方法一:使用任务管理器杀死进程打开任务管理器->查看->选择列->然后勾选PID选项,回到任务 ...
- kuma 学习三 组件说明
当前官方已经提供了两种可选的运行模式 通用模式 kubernetes 模式 kuma 组件说明 kuma-cp kuma 的控制面板 kuma-dp kuma 的数据面板 enovy 提供sideca ...
- dotnetcore docker 简单运行
今天试用了下mac 版本的dotnetcore sdk,发现还是很方便的,同时官方的容器运行方式,相对小了好多 同时使用多阶段构建的方式运行dotnetcore 安装sdk 下载地址: https:/ ...
- luogu P3799 妖梦拼木棒
二次联通门 : luogu P3799 妖梦拼木棒 /* luogu P3799 妖梦拼木棒 用一个桶存下所有的木棒 美剧两根短的木棒长度 后随便乘一乘就 好了.. */ #include <a ...
- 洛谷P2607题解
想要深入学习树形DP,请点击我的博客. 本题的DP模型同 P1352 没有上司的舞会.本题的难点在于如何把基环树DP转化为普通的树上DP. 考虑断边和换根.先找到其中的一个环,在上面随意取两个点, 断 ...
- shell 命令行参数(基本)
命令行参数 $0 表示程序名.$1 至 \$9则是位置参数.$# 表示参数的个数.$* 将所有参数当做一个整体来引用$@ 把每个参数作为一个字符串返回,可以使用for循环来遍历$? 最近一个执行的命令 ...
- Siam R-CNN: Visual Tracking by Re-Detection
Siam R-CNN: Visual Tracking by Re-Detection 2019-12-02 22:21:48 Paper:https://128.84.21.199/abs/1911 ...