百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

什么是注解?为什么要使用注解?理解下annotation?

zhezhongyun 2024-12-03 06:31 92 浏览

推荐学习

一、什么是注解?

  从 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.
  • 只有当元注释类型直接用于注释时,保留元注释才有效。如果元注释类型被用作另一个注释类型中的成员类型,则没有效果。

间而言之:

  此注解主要作用为在什么级别保存该注解信息,用于描述注解的声明周期,需要主要的是 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枚举常量

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{

}

五、总结

  总的来说,注解还是比较简单的。

作者: 学海无涯519

原文链接:https://www.cnblogs.com/wgx519/p/14373086.html

相关推荐

Python入门学习记录之一:变量_python怎么用变量

写这个,主要是对自己学习python知识的一个总结,也是加深自己的印象。变量(英文:variable),也叫标识符。在python中,变量的命名规则有以下三点:>变量名只能包含字母、数字和下划线...

python变量命名规则——来自小白的总结

python是一个动态编译类编程语言,所以程序在运行前不需要如C语言的先行编译动作,因此也只有在程序运行过程中才能发现程序的问题。基于此,python的变量就有一定的命名规范。python作为当前热门...

Python入门学习教程:第 2 章 变量与数据类型

2.1什么是变量?在编程中,变量就像一个存放数据的容器,它可以存储各种信息,并且这些信息可以被读取和修改。想象一下,变量就如同我们生活中的盒子,你可以把东西放进去,也可以随时拿出来看看,甚至可以换成...

绘制学术论文中的“三线表”具体指导

在科研过程中,大家用到最多的可能就是“三线表”。“三线表”,一般主要由三条横线构成,当然在变量名栏里也可以拆分单元格,出现更多的线。更重要的是,“三线表”也是一种数据记录规范,以“三线表”形式记录的数...

Python基础语法知识--变量和数据类型

学习Python中的变量和数据类型至关重要,因为它们构成了Python编程的基石。以下是帮助您了解Python中的变量和数据类型的分步指南:1.变量:变量在Python中用于存储数据值。它们充...

一文搞懂 Python 中的所有标点符号

反引号`无任何作用。传说Python3中它被移除是因为和单引号字符'太相似。波浪号~(按位取反符号)~被称为取反或补码运算符。它放在我们想要取反的对象前面。如果放在一个整数n...

Python变量类型和运算符_python中变量的含义

别再被小名词坑哭了:Python新手常犯的那些隐蔽错误,我用同事的真实bug拆给你看我记得有一次和同事张姐一起追查一个看似随机崩溃的脚本,最后发现罪魁祸首竟然是她把变量命名成了list。说实话...

从零开始:深入剖析 Spring Boot3 中配置文件的加载顺序

在当今的互联网软件开发领域,SpringBoot无疑是最为热门和广泛应用的框架之一。它以其强大的功能、便捷的开发体验,极大地提升了开发效率,成为众多开发者构建Web应用程序的首选。而在Spr...

Python中下划线 ‘_’ 的用法,你知道几种

Python中下划线()是一个有特殊含义和用途的符号,它可以用来表示以下几种情况:1在解释器中,下划线(_)表示上一个表达式的值,可以用来进行快速计算或测试。例如:>>>2+...

解锁Shell编程:变量_shell $变量

引言:开启Shell编程大门Shell作为用户与Linux内核之间的桥梁,为我们提供了强大的命令行交互方式。它不仅能执行简单的文件操作、进程管理,还能通过编写脚本实现复杂的自动化任务。无论是...

一文学会Python的变量命名规则!_python的变量命名有哪些要求

目录1.变量的命名原则3.内置函数尽量不要做变量4.删除变量和垃圾回收机制5.结语1.变量的命名原则①由英文字母、_(下划线)、或中文开头②变量名称只能由英文字母、数字、下画线或中文字所组成。③英文字...

更可靠的Rust-语法篇-区分语句/表达式,略览if/loop/while/for

src/main.rs://函数定义fnadd(a:i32,b:i32)->i32{a+b//末尾表达式}fnmain(){leta:i3...

C++第五课:变量的命名规则_c++中变量的命名规则

变量的命名不是想怎么起就怎么起的,而是有一套固定的规则的。具体规则:1.名字要合法:变量名必须是由字母、数字或下划线组成。例如:a,a1,a_1。2.开头不能是数字。例如:可以a1,但不能起1a。3....

Rust编程-核心篇-不安全编程_rust安全性

Unsafe的必要性Rust的所有权系统和类型系统为我们提供了强大的安全保障,但在某些情况下,我们需要突破这些限制来:与C代码交互实现底层系统编程优化性能关键代码实现某些编译器无法验证的安全操作Rus...

探秘 Python 内存管理:背后的神奇机制

在编程的世界里,内存管理就如同幕后的精密操控者,确保程序的高效运行。Python作为一种广泛使用的编程语言,其内存管理机制既巧妙又复杂,为开发者们提供了便利的同时,也展现了强大的底层控制能力。一、P...