关于Java注解(annotation)的简单理解
一、什么是注解?
从 JDK5 开始,Java增加对元数据的支持,也就是注解。简单理解就是代码里的特殊标志,这些标志可以在编译,类加载,运行时被读取,并执行相应的处理,以便于其他工具补充信息或者进行部署。
二、为什么要使用注解?
注解可以被其他程序(比如:编译器等)读取,开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。
三、注解的相关概述
3.1 注解的格式
注解就是以 @XXX 形式在代码中存在的,我们还可以为注解添加一些参数值,例如 @SuppressWarnings(value = "unchecked") 。
3.2 元注解
元注解就是负责注解其它注解的注解。
下图为Java定义的标准的 元注解类型,他们用来对其他的注解进行说明,可以在 Java API 的 java.lang.annotation 包中找到。

3.2.1 @Document
官方示例:
// since 1.5
@Documented
@Retention(RUNTIME)
@Target(ANNOTATION_TYPE)
public @interface Documented
官方描述:
- 如果注释@Documented出现在注释类型A的声明中,那么元素上的任何@A注释都被认为是元素公共契约的一部分。
- 更详细地说,当使用Documented对注释类型A进行注释时,类型A的注释的存在和值是A注释的元素的公共契约的一部分。相反,如果注释类型B没有被文档化注释,那么B注释的存在和值就不是B注释元素的公共契约的一部分。
- 具体地说,如果注释类型是用Documented注释的,那么默认情况下,像javadoc这样的工具将在其输出中显示该类型的注释,而没有Documented的注释类型的注释将不会显示。
间而言之:
如果使用了 @Documented ,就说明此类(或方法、字段等)的文档化注释就会被包含在JavaDoc中。
3.2.2 @Inherited
官方示例:
// since 1.5
@Documented
@Retention(RUNTIME)
@Target(ANNOTATION_TYPE)
public @interface Inherited
官方描述:
- 指示自动继承批注类型。
- 如果在注释类型声明上存在继承的元注释,并且用户在类声明上查询注释类型,而该类声明对此类型没有注释,则将自动在类的超类中查询注释类型。将重复此过程,直到找到此类型的注释,或到达类层次结构(对象)的顶部。
如果没有超类具有此类型的注释,则查询将指示所讨论的类没有此类注释。 - 请注意,如果注释类型用于注释类以外的任何内容,则此元注释类型无效。还要注意,这个元注释只会导致注释从超类继承;对实现接口的注释没有影响。
简而言之:
子类可以继承父类(超类)中的该注解。这个注解指定被他修饰的注解将具有继承性——如果某个类使用了@XXX,则其子类将自动被@XXX修饰
代码示例:
1 public class test2 {
2
3 public static void main(String[] args) {
4 Person person = new Person();
5 Student student = new Student();
6
7 Annotation[] parentAnnotation = person.getClass().getAnnotations();
8 Annotation[] studentAnnotation = student.getClass().getAnnotations();
9 for (Annotation annotation : parentAnnotation) {
10 System.out.println(annotation);
11 }
12 System.out.println("---------------------");
13 for (Annotation annotation : studentAnnotation) {
14 System.out.println(annotation);
15 }
16
17 // 输出结果
18 // @com.ruiyicloud.bbfbusiness.demo.annotation.MyAnnotation3()
19 // ---------------------
20 // @com.ruiyicloud.bbfbusiness.demo.annotation.MyAnnotation3()
21
22 }
23
24
25 }
26
27 @Target({ElementType.TYPE})
28 @Retention(RetentionPolicy.RUNTIME)
29 @Inherited
30 @interface MyAnnotation3{
31
32 }
33 @MyAnnotation3
34 class Person{
35 String name;
36 }
37
38 class Student extends Person{
39 int age;
40 }
注意:
如果 MyAnnotation3 注解 去掉 @Inherited,则student.getClass().getAnnotations() 将输入空。
3.2.3 @Native
官方代码:
// since 1.8
@Documented
@Target(FIELD)
@Retention(SOURCE)
public @interface Native
官方描述:
指示定义常量值的字段可以从本机代码引用。生成本机头文件的工具可以使用该注释作为提示,以确定是否需要头文件,如果需要,还应该包含哪些声明。
间而言之:
使用本地方法,我们可以用java与底层系统的交互,如果使用Java获取不到我们想要的内容,我们可以选择使用本地方法。
使用 @Native 注解修饰变量值的字段,则表示这个变量可以被本地代码引用。
代码示例:
附上Integer的部分源码
1 public final class Integer extends Number
2 implements Comparable<Integer>, Constable, ConstantDesc {
3 /**
4 * A constant holding the minimum value an {@code int} can
5 * have, -2<sup>31</sup>.
6 */
7 @Native public static final int MIN_VALUE = 0x80000000;
8
9
10
11 // 比较值的大小
12 public static int compareUnsigned(int x, int y) {
13 return compare(x + MIN_VALUE, y + MIN_VALUE);
14 }
3.2.4 @Repeatable
官方代码:
// since 1.8
@Documented
@Retention(RUNTIME)
@Target(ANNOTATION_TYPE)
public @interface Repeatable
官方描述:
注释类型java.lang.annotation注释.Repeatable用于指示它(meta-)注释其声明的注释类型是可重复的。@Repeatable的值表示可重复注释类型的包含注释类型。
间而言之:
使用@Repeatable这个声明的注解是可重复的。@Repeatable的值是另一个注解,其可以通过这个另一个注解的值来包含这个可重复的注解。
代码示例:
FooContainer 作用于范围只能在注解类型上,所以作用于接口上时会报错
1 import java.lang.annotation.ElementType;
2 import java.lang.annotation.Repeatable;
3 import java.lang.annotation.Target;
4
5 public class test03 {
6
7 }
8
9
10 @Target({ElementType.TYPE,ElementType.ANNOTATION_TYPE})
11 @Repeatable(FooContainer.class)
12 @interface Foo {}
13
14 @Target(ElementType.ANNOTATION_TYPE)
15 @interface FooContainer {
16 Foo[] value();
17 }
18
19 //正确的
20 @Foo @Foo
21 @interface FooContainer1 {
22 Foo[] value();
23 }
24
25 // 错误的
26 @Foo @Foo
27 interface aa {
28
29 }
注意事项:
- Foo的保留时间至少与FooContainer一样长,其中保留用@Retention 注释显式或隐式表示。特别:
- 如果Foo的保留为java.lang.annotation.RetentionPolicy.SOURCE,则FooContainer的保留为java.lang.annotation.RetentionPolicy.SOURCE。
- 如果Foo的保留值为java.lang.annotation.RetentionPolicy.CLASS,则FooContainer的保留值为java.lang.annotation.RetentionPolicy.CLASS或 java.lang.annotation.RetentionPolicy.SOURCE。
- 如果保留Foo是java.lang.annotation.RetentionPolicy.RUNTIME,则保留FooContainer是java.lang.annotation.RetentionPolicy.SOURCE, java.lang.annotation.RetentionPolicy.CLASS,或java.lang.annotation.RetentionPolicy.RUNTIME。
3.2.5 @Retention
官方示例:
// since 1.5
@Documented
@Retention(RUNTIME)
@Target(ANNOTATION_TYPE)
public @interface Retention
官方描述:
- 指示带批注类型的批注要保留多长时间。如果批注类型声明上不存在保留批注,则保留策略默认为保留策略.CLASS.
- 只有当元注释类型直接用于注释时,保留元注释才有效。如果元注释类型被用作另一个注释类型中的成员类型,则没有效果。
| 枚举常量 | 描述 |
|---|---|
CLASS |
枚举常量将由编译器记录在类文件中,但不需要在运行时由VM保留.
|
RUNTIME |
注释将由编译器记录在类文件中,并在运行时由VM保留,因此可以反射地读取它们.
|
SOURCE |
注释将被编译器丢弃.
|
间而言之:
此注解主要作用为在什么级别保存该注解信息,用于描述注解的声明周期,需要主要的是 SOURCE < CLASS < RUNTIME 。
3.2.6 @Target
官方示例:
// since 1.5
@Documented
@Retention(RUNTIME)
@Target(ANNOTATION_TYPE)
public @interface Target
官方描述:
- 指示批注类型适用的上下文。JLS 9.6.4.1中指定了可应用注释类型的声明上下文和类型上下文,并在源代码中用java.lang.annotation注释.ElementType。
- 如果@Target元注释不存在于注释类型T上,那么类型T的注释可以作为除类型参数声明之外的任何声明的修饰符来编写。
- 如果存在@Target元注释,编译器将根据JLS 9.7.4强制执行由ElementType enum常量指示的使用限制。
简而言之:
@Target注解主要用于描述注解的使用范围(例如,添加某些属性的时候注解可以使用在类上,添加某些属性的时候注解可以使用在方法上等)
3.3 注解的使用范围?
ElementType枚举常量 |
作用范围 |
| TYPE | 类、接口(包括注释类型)、枚举或记录 |
| FIELD | 字段声明(包括枚举常量) |
| METHOD | 方法声明 |
| PARAMETER | 形式参数声明 |
| CONSTRUCTOR | 构造函数声明 |
| LOCAL_VARIABLE | 局部变量声明 |
| ANNOTATION_TYPE | 注解类型声明 |
| PACKAGE | 包声明 |
| TYPE_PARAMETER | 类型参数声明(since 8) |
| TYPE_USE | 类型的使用(since 8) |
| MODULE | 模块声明 (since 9) |
| RECORD_COMPONENT | Java语言的一种预览功能(since 14) |
3.4 常用的几个注解
@Override :
限定父类重写方法,当子类重写父类方法时,子类可以加上这个注解,可以确保子类确实重写了父类的方法,避免出现低级错误。
@FunctionalInterface:
函数式接口,注解保证这个接口只有一个抽象方法,注意这个只能修饰接口。(函数式接口是指 接口中只有一个抽象方法(可以包含多个默认方法或多个static方法),接口体内只能声明常量字段和抽象方法,并且被隐式声明为public,static,final。接口里面不能有私有的方法或变量。)
@Deprecated:
标示已过时,这个注解用于表示某个程序元素类,方法等已过时,当其他程序使用已过时的类,方法时编译器会给出警告。
@SuppressWarning:
抑制编译器警告,被该注解修饰的元素以及该元素的所有子元素取消显示编译器警告。
四、自定义注解实战
本例创建一个简单的注解,并在方法上、类上进行使用
@MyAnnotation
public class Main {
@MyAnnotation
public static void main(String[] args) { }
} // Target 标识注解可以在什么地方使用
@Target({ElementType.METHOD,ElementType.TYPE})
// 标识此注解在什么地方还有效
@Retention(RetentionPolicy.RUNTIME)
// 标识是否将我们的注解生成在JavaDoc中
@Documented
// 子类可以继承父类的注解
@Inherited
@interface MyAnnotation{ }
五、总结
总的来说,注解还是比较简单的。
关于Java注解(annotation)的简单理解的更多相关文章
- 深入JAVA注解-Annotation(学习过程)
JAVA注解-Annotation学习 本文目的:项目开发过程中遇到自定义注解,想要弄清楚其原理,但是自己的基础知识不足以支撑自己去探索此问题,所以先记录问题,然后补充基础知识,然后解决其问题.记录此 ...
- 深入学习JAVA注解-Annotation(学习过程)
JAVA注解-Annotation学习 本文目的:项目开发过程中遇到自定义注解,想要弄清楚其原理,但是自己的基础知识不足以支撑自己去探索此问题,所以先记录问题,然后补充基础知识,然后解决其问题.记录此 ...
- Java注解Annotation(一)
Java注解Annotation(一)——简介 这一章首先简单介绍一下注解,下一章会给出一个注解应用的DEMO. 1. 元注解 元注解的作用是负责注解其他的注解. JDK1.5中,定义了4个标准的me ...
- Java注解Annotation与自定义注解详解
Java注解简介 开发中经常使用到注解,在项目中也偶尔会见到过自定义注解,今天就来探讨一下这个注解是什么鬼,以及注解的应用场景和如何自定义注解. 下面列举开发中常见的注解 @Override:用于标识 ...
- Java - 注解 (Annotation)
Java - 注解 (Annotation) 一.基本的 Annotation > 使用 Annotation 时要在其前面增加 @符号,并把该 Annotation 当成一个修饰符 ...
- Java注解(Annotation)详解
转: Java注解(Annotation)详解 幻海流心 2018.05.23 15:20 字数 1775 阅读 380评论 0喜欢 1 Java注解(Annotation)详解 1.Annotati ...
- java注解Annotation
扯扯注解的蛋 为什么学习注解?学习注解有什么好处?学完能做什么? 1.能够读懂别人的代码,特别是框架相关的代码 2.让编程更加简洁,代码更加清晰 3.让别人高看你一眼 注解是java1.5引入的 概念 ...
- 秒懂,Java 注解 (Annotation)你可以这样学 - CSDN博客
https://blog.csdn.net/briblue/article/details/73824058 文章开头先引入一处图片. 这处图片引自老罗的博客.为了避免不必要的麻烦,首先声明我个人比较 ...
- XML注释与Description标签及Java:注解(Annotation)的关系
NET中的规范标准注释(一) -- XML注释标签讲解 一.摘要 .Net允许开发人员在源代码中插入XML注释,这在多人协作开发的时候显得特别有用. C#解析器可以把代码文件中的这些XML标记提取出来 ...
- java注解(Annotation)解析
注解(Annotation)在java中应用非常广泛.它既能帮助我们在编码中减少错误,(比如最常见的Override注解),还可以帮助我们减少各种xml文件的配置,比如定义AOP切面用@AspectJ ...
随机推荐
- Win Task 任务管理器 批量杀进程方法
Example Kill All Chrome & Chrome Driver taskkill /IM chromedriver.exe /F taskkill /IM chrome.exe ...
- WPF 关于拖拽打开文件的注意事项
由于开发需求,需要开发一个类似Win图片浏览的工具 当然也涉及到了拖拽打开的需求 按照固有思路: <Grid x:Name="grid1" AllowDrop="T ...
- Goland 设置代码格式化
前言 之前一直喜欢 VsCode 的代码自动格式化和其他的一些功能 今天了解到原来 Goland 也有这些功能, 想想也对, 毕竟这么大 正文 Goland设置代码格式化 进入设置,按需选择要使用的, ...
- Java向指定Excel写入读取数据
今天在开发中遇到用户列表导入导出的功能实现,这里了解到使用POI函数库可以完成此任务!特此记录一下 POI Apache POI是Apache软件基金会开放的源码函数库,POI提供API给Java程序 ...
- python学习笔记 | 列表去重
''' @author: 人人都爱小雀斑 @time: 2020/3/10 10:29 @desc: ''' L=[1,5,7,4,6,3,0,5,8,4,4] 方法1:for循环 L1=[] for ...
- ssl证书与java keytool工具
ssl协议 SSL(Secure Sockets Layer 安全套接字协议),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安 ...
- linux中进制转换
方式一:使用$[]或$(()) 格式为:$[base#number]或$((base#number)),其中base为进制,number为对应进制数. 这种方式输入2进制.16进制等,但只能输出为10 ...
- [Ceoi2004]Journey
题目描述 给出N个点,及你的出发点K. 接下来N-1行描述有关边的开始点,结束点,边长.保证图中不会有环 接下来给出数字J,代表你要走多少个点. 接下来J个数字,代表你要走过的点的编号.当然你可以自己 ...
- ECharts图表——封装通用配置
前言 前段时间在做大屏项目,大量用到echarts图表,大屏对设计规范要求比较高,而大屏项目,经常会因为业务方面的原因.或者是数据方面的原因改动UI设计,所有图表的代码也是三天一小改.五天一大改 因此 ...
- 三节锂电池充电管理芯片,IC电路图如何设计
关于三节锂电池供电的产品,在三节锂电池上,需要三个电路系统: 1,三节锂电池保护电路, 2,三节锂电池充电电路, 3,三节锂电池输出电路. 1.三节锂电池保护电路,芯片电路图 控制三节锂电池池的充电电 ...