Java 入门指南:注解(Annotation)

news2024/11/26 18:29:00

注解的基本概念

Java注解(Annotation)是一种附加在代码中的元数据,用于对程序代码进行说明和补充。同 class 类interface 接口 一样,也属于一种类型。它是在 Java SE 5 中引入的一项新特性,常用于配置、编译和运行时的处理。但是注解并不是所装饰代码的一部分,它对代码的运行效果没有直接影响。

主要的作用有以下四方面:

  • 生成文档,通过代码里标识的元数据生成 javadoc 文档。

  • 编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证。

  • 编译时动态处理,编译时通过代码里标识的元数据动态处理,例如动态生成代码。

  • 运行时动态处理,运行时通过代码里标识的元数据动态处理,例如使用反射注入实例。

注解以 @注解名 格式出现在代码中,可以用于对包、接口、类、方法、变量、参数等进行标注。Java 提供了很多内置注解,如 @Override@Deprecated@SuppressWarnings 等,也可以自定义注解。

注解的好处是能够在不影响程序执行的情况下提供额外的信息,使得代码更加灵活、可读性更强、易于维护和修改。同时也方便一些工具对代码进行分析和处理,例如 IDE、编译器、代码生成器等。

Java注解的应用场景

Java注解在软件开发中具有广泛的应用场景,包括但不限于:

  1. 代码生成:在编译时自动生成额外的代码,如Lombok库中的 @Data@NoArgsConstructor 等注解,用于自动生成 getter/setter 方法、构造函数等。

  2. 编译时检查:通过注解在编译时进行格式检查,如 @Override 注解确保方法正确重写了父类中的方法。

  3. 框架配置:在Spring等框架中,通过注解简化配置,如 @Component@Service@Repository 等注解用于声明Bean,@Autowired 用于依赖注入。

  4. 运行时处理:在运行时读取注解信息,实现动态行为,如日志记录、性能监控等。

  5. 文档生成:通过注解生成 API 文档,如 Javadoc 工具可以读取注解信息并生成文档。

Java 内置注解

Java语言内置了多个注解,这些注解用于提供对程序代码附加的元数据说明,有些用于编译期间的检查,有些用于运行期间的处理。

@Override

@Override 用于表示一个方法覆盖了其超类中的方法。它可以帮助开发人员避免在方法重写时出现错误的签名或拼写错误。

![[Pasted image 20231208153537.png]]

使用 @Override 注解的方法必须满足以下条件:

  1. 必须是一个实例方法(非 staticfinal 方法);

  2. 方法签名与超类中的方法完全相同

如果满足以上条件,使用 @Override 标注的方法在编译时将会受到更严格的检查。如果方法的签名不正确,编译器将提示一个错误,这有助于避免由于拼写错误或方法签名不匹配导致的编译错误。

@Deprecated

@Deprecated 用于标示某个程序元素(类、方法、字段等)已经过时,不再推荐使用。当开发人员使用被标注为 @Deprecated 的元素时,编译器会发出警告。

![[Pasted image 20231208153648.png]]

使用 @Deprecated 注解的作用是向程序员传达某个元素已经过时,不再是首选的选择,可能存在更好的替代方案。通过标记过时的元素,可以帮助开发人员避免使用不再维护或存在缺陷的代码,以提高代码的质量和可维护性。

虽然 @Deprecated 注解并不会阻止代码的使用,但是作为开发人员,应该尽量遵循注解的意图,考虑使用推荐的替代方案。

@SuppressWarning

@SuppressWarnings 用于抑制编译期间产生的一些警告信息。当某个代码段出现编译器警告,且确定这个警告并不是一个真正的问题时,可以使用 @SuppressWarnings 注解来消除这些警告。

![[Pasted image 20231208153700.png]]

@SuppressWarnings 注解可以应用于很多不同的警告类型,具体的警告类型取决于编译器和开发环境。

例如,常见的警告类型包括未使用变量、弃用方法的使用、类型转换的安全性等。

虽然 @SuppressWarnings 注解可以消除编译器警告,但在使用时应谨慎,确保真正了解警告的原因,并确认忽略这些警告是安全的。避免过度使用 @SuppressWarnings 注解,以免掩盖真正的问题和潜在的错误。

@Suppress(" ") 可取值
参数作用
all抑制所有警告
boxing抑制装箱、拆箱操作时候的警告
cast抑制映射相关的警告
dep-ann抑制启用注释的警告
deprecation抑制过期方法警告
fallthrough抑制确在switch中缺失breaks的警告
finally抑制finally模块没有返回的警告
hiding抑制与隐藏变数的区域变数相关的警告
incomplete-switch忽略没有完整的switch语句
nls忽略非nls格式的字符
null忽略对null的操作
rawtype使用generics时忽略没有指定相应的类型
restriction抑制与使用不建议或禁止参照相关的警告
serial忽略在serializable类中没有声明serialVersionUID变量
static-access抑制不正确的静态访问方式警告
synthetic-access抑制子类没有按最优方法访问内部类的警告
unchecked抑制没有进行类型检查操作的警告
unqualified-field-access抑制没有权限访问的域的警告
unused抑制没被使用过的代码的警告

元注解

元注解(Meta-Annotations)是用于注解其他注解的注解。元注解提供了对注解进行更精细的控制和定义。

@Retention

@Retention 用于指定注解的保留策略,即注解可以在何时可用。它可以被用于定义其他注解。

@Retention 元注解有一个 value 属性,用于指定保留策略。可选的保留策略包括:

  • RetentionPolicy.SOURCE:注解仅在源代码级别可见,在编译之后不会包含在编译后的字节码中。

  • RetentionPolicy.CLASS:注解在编译时保留,在编译后的字节码中可见,但在运行时不可通过 反射 获取注解信息(默认值)。

  • RetentionPolicy.RUNTIME:注解在运行时保留,可以通过反射获取注解信息,并根据注解的定义执行相应的代码,对运行时的代码有影响。

自定义注解的保留策略如果不指定,默认为 RetentionPolicy.CLASS

编译器分别使用了 RuntimeInvisibleAnnotationsRuntimeVisibleAnnotations 属性去记录了 RetentionPolicy.CLASS 注解的方法 和 @RetentionPolicy.RUNTIME 方法 的注解信息

@Target

@Target 用于指定它所注解的注解类可以应用的目标元素类型。它可以被用于定义其他注解。

@Target 元注解有一个 value 属性,类型为 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:声明语句、泛型或强制转换类型语句中的类型

  • ElementType.MODULE:模块

多个目标元素类型可以用数组的形式进行指定。

@Documented

@Documented 用于指定被它注解的注解是否应该包含在自动生成的 API 文档(Javadoc)中。它可以被用于定义其他注解。

@Documented 只是一个标记,它本身并不会影响注解的使用和行为。只有在生成 API 文档时才会体现其作用。

通常情况下,如果开发者希望在 API 文档中包含某个注解的信息,就可以为该注解添加 @Documented 元注解。如果不需要在 API 文档中包含注解信息,可以不添加该注解。

@Inherited

@Inherited 用于指定被它注解的 Annotation 是否可以被子类继承。它可以被用于定义其他注解。

![[Pasted image 20231208212434.png]]

如果一个注解被标注了 @Inherited,并且被应用于一个父类上,那么子类会自动继承该注解,除非子类自己显式声明了相同的注解。

需要注意的是,@Inherited 只会作用于类级别的注解。对于其他类型的元素(如方法、字段等)的注解,无论是否标注了 @Inherited,子类都不会继承父类的注解。

通常情况下,只有当注解的语义与继承相关时,才需要使用 @Inherited 注解。对于大多数注解来说,不需要使用 @Inherited 注解。

@Repeatable

@Repeatable ,是从 Java 8 开始引入的特性,用于指定某个注解是否可以被多次应用于同一个元素。它可以被用于定义其他注解。

要使用 @Repeatable,需要满足以下两个条件:

  1. 定义一个包含重复注解的容器注解(如 MyAnnotations)。
  2. 将容器注解的类型指定为 @Repeatable 注解的 value 属性。

使用 @Repeatable 后,可以通过在同一个元素上多次应用注解,简化代码编写。例如,可以在同一个方法上重复应用相同的注解,而不需要将注解放置在一个包含数组的容器注解中。

@Native

@Native 是一个用于标记方法或类的注解,表示该方法或类是由本地代码(如 C、C++ 或其他本地语言)实现的。它是 Java 本地方法接口(Java Native Interface,JNI)的一部分。

@Native 注解通常与 native 关键字一起使用,用于标识需要调用本地代码实现的方法。native 关键字用于声明一个方法是本地方法,而 @Native 注解则为编译器提供额外的信息,指示该方法的实现由本地代码提供。

需要注意的是,使用本地方法时需要使用 JNI 编写对应的本地代码。本地代码通常是使用 C 或 C++ 编写的,通过 JNI 扩展与 Java 代码进行交互。

在 Java 中,本地方法的调用和实现通过 JNI 提供的接口进行连接。Java 虚拟机(JVM)会加载并执行本地代码,从而使 Java 代码能够调用本地方法。

使用本地方法可以实现与底层系统的交互、调用本地库、执行性能敏感的操作等。但需要注意,在使用本地方法时需谨慎处理内存管理和跨平台的兼容性问题。

注解和反射接口

反射包 java.lang.reflect 下的 AnnotatedElement 接口提供这些方法。这里注意:只有注解被定义为 RUNTIME 后,该注解才能是运行时可见,当 class 文件被装载时被保存在 class 文件中的 Annotation 才会被虚拟机读取。

AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通过反射获取了某个类的AnnotatedElement 对象之后,程序就可以调用该对象的方法来访问Annotation 信息。

自定义注解

@interface

@interface 是 Java 中用于创建自定义注解的关键字。使用 @interface 可以定义一个新的注解类型,并在注解中声明自定义的元素。

下面是 @interface 的语法格式:

public @interface 注解名 {
    // 注解元素声明
}

@interface 定义的花括号中,可以声明注解的元素。注解元素的定义类似于方法的定义,包括元素的类型、名称和可选的默认值。

一般步骤

自定义注解是使用 Java 的注解机制创建自己的注解。下面是创建自定义注解的一般步骤:

  1. 使用 @interface 关键字定义一个新的注解类型。
  2. 声明注解的元素,这些元素就是我们希望在注解中指定的值。
  3. 使用元注解(如 @Retention@Target 等)来配置注解的行为。

下面是一个示例,假设我们要创建一个 Person 注解,用于标识人员信息。该注解包含两个元素:姓名和年龄。

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Person {
    String name();
    int age();
}

在上面的例子中,我们使用 @interface 关键字定义了 Person 注解。注解元素 nameage 分别用来表示人员的姓名和年龄。@Retention(RetentionPolicy.RUNTIME) 表示该注解在运行时可用,@Target(ElementType.TYPE) 表示该注解可修饰类和接口。

使用自定义注解时,我们可以像使用其他注解一样将其应用于类或接口,例如:

@Person(name = "Alice", age = 25)
public class MyClass {
    // ...
}

在上面的示例中,我们将 @Person 注解应用于 MyClass 类,指定了姓名为 “Alice”,年龄为 25。

需要注意的是,自定义注解的元素可以有默认值,如下所示:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Person {
    String name() default "Unknown";
    int age() default 0;
}

在上面的修改中,我们为 nameage 元素指定了默认值,当使用 @Person 注解时,如果不指定这些元素的值,它们将取默认值。

自定义注解可以通过反射技术在运行时获取注解信息,并根据注解信息进行相应的处理。

相关接口

  • boolean isAnnotationPresent(Class<?extends Annotation> annotationClass)

    判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false。注意:此方法会忽略注解对应的注解容器。

  • <T extends Annotation> T getAnnotation(Class<T> annotationClass)

    返回该程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null。

  • Annotation[] getAnnotations()

    返回该程序元素上存在的所有注解,若没有注解,返回长度为0的数组。

  • <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass)

    返回该程序元素上存在的、指定类型的注解数组。没有注解对应类型的注解时,返回长度为0的数组。该方法的调用者可以随意修改返回的数组,而不会对其他调用者返回的数组产生任何影响。

    getAnnotationsByType方法与 getAnnotation的区别在于,getAnnotationsByType会检测注解对应的重复注解容器。

    若程序元素为类,当前类上找不到注解,且该注解为可继承的,则会去父类上检测对应的注解。

  • <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)

    返回直接存在于此元素上的所有注解。与此接口中的其他方法不同,该方法将忽略继承的注释。如果没有注释直接存在于此元素上,则返回null

  • <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass)

    返回直接存在于此元素上的所有注解。与此接口中的其他方法不同,该方法将忽略继承的注释

  • Annotation[] getDeclaredAnnotations()

    返回直接存在于此元素上的所有注解及注解对应的重复注解容器。与此接口中的其他方法不同,该方法将忽略继承的注解。

    如果没有注释直接存在于此元素上,则返回长度为零的一个数组。该方法的调用者可以随意修改返回的数组,而不会对其他调用者返回的数组产生任何影响。

Java注解的实例

以下是一个简单的自定义注解及其使用的示例:

// 自定义注解  
@Retention(RetentionPolicy.RUNTIME)  
@Target(ElementType.METHOD)  
public @interface MyAnnotation {  
    String value() default "default value";  
}  
  
// 使用自定义注解  
public class MyClass {  
    @MyAnnotation(value = "custom value")  
    public void myMethod() {  
        // 方法实现  
    }  
}  
  
// 运行时读取注解信息  
public class AnnotationReader {  
    public static void main(String[] args) {  
        Method method = MyClass.class.getMethod("myMethod");  
        if (method.isAnnotationPresent(MyAnnotation.class)) {  
            MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);  
            System.out.println(annotation.value()); // 输出:custom value  
        }  
    }  
}

总结

Java注解是Java语言中一个非常重要的特性,它为Java程序提供了一种灵活的方式来添加元数据。通过注解,开发者可以在不修改代码逻辑的情况下,为代码添加额外的信息,这些信息可以在编译时、加载时或运行时被读取和处理。掌握Java注解的使用,对于提高Java编程的灵活性和可维护性具有重要意义。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2060929.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux信号的保存与信号的处理

目录 前言 一、信号保存 1、重谈信号的概念 2、信号在内核中的表示 3、sigset_t 4、信号集操作函数、 • sigset_t相关的接口 • sigpromask • sigpending 二、信号处理 1、再谈地址空间 2、用户态与内核态 • 内核态和用户态的切换 • 用户态切换为内核态的几种…

软件开发的航海之旅:程序员的实用神器

在软件开发的海洋中&#xff0c;程序员们就像勇敢的航海家&#xff0c;驾驭着代码的航船&#xff0c;向着未知的目的地进发。在这个过程中&#xff0c;各种实用的开发工具就如同航海中的指南针&#xff0c;帮助他们导航、加速开发、优化代码质量&#xff0c;并最终抵达成功的彼…

YOLO-V3

一、概述 最大的改进就是网络结构&#xff0c;使其更适合小目标检测特征做的更细致&#xff0c;融入多持续特征图信息来预测不同规格物体先验框更丰富了&#xff0c;3种scale&#xff0c;每种3个规格&#xff0c;一共9种softmax改进&#xff0c;预测多标签任务 先验框&#xf…

dubbo:dubbo+nacos整合springcloud gateway实现网关(三)

文章目录 0. 引言1. 集成gateway网关1.1 实操步骤1.2 dubbo提供者注册到nacos出现两个实例的问题 2. 源码3. 总结 0. 引言 上次我们讲到使用zookeeper作为注册中心搭建dubbo微服务框架&#xff0c;但是我们还缺少一个服务总入口&#xff0c;也就是我们的网关服务。所以今天我们…

小兔鲜首页制作css

一、项目目录 项目名-客户端 xtx-pc 1.images&#xff1a;存放固定使用的图片&#xff0c;例如&#xff1a;logo、样式修饰图 2.uploads:存放非固定图片&#xff0c;例如&#xff1a;商品图、宣传图等需要上传的图片 3.iconfont:字体图标素材 4.css文件&#xff1a; 4.1base.cs…

猫咪除毛除臭大作战!宠物空气净化器帮助铲屎官轻松应对换毛季

最近天气真的好热&#xff0c;可以的话真想呆在空调房一直不出来&#xff0c;人都受不了&#xff0c;何况是一身厚重毛发的猫咪。这不&#xff0c;本该在春季结束的换毛季&#xff0c;延续到了夏天。它就像一个行走的蒲公英&#xff0c;家里到处散落着它的毛发。体臭和便臭在密…

【软件测试·研究向】Major 变异测试工具使用教程

目录 前言 1 安装 1.1 下载解压 1.2 配置环境变量 1.3 入门示例脚本 2 Mutator Plugin 编译器插件 2.1 如何使用插件&#xff1f; 2.2 插件配置选项 2.3 Major 支持的变异算子 2.4 突变体的日志记录 2.5 生成突变体的源代码 3 构建系统集成 4 Major 突变语言 (M…

系统架构设计师:信息系统概述及分类

信息系统是由计算机硬件、网络和通信设备、计算机软件、信息资源、信息用户和规章制度组成的以处理信息流为目的的人机一体化系统。 从技术上可以定义为一系列支持决策和控制的相关要素&#xff0c;这些要素主要包括信息的收集、检索、加工处理和信息服务。除了支持决策、协作…

【Python】动态类型、输入和输出、条件语句

动态类型 程序运行过程中&#xff0c;变量的类型可能会发生改变 a hello print(a) a 10 print(a)#运行结果 hello 10在程序执行过程中&#xff0c;a 的类型刚开始是 int&#xff0c;后面变成了 str C / Java 这样的语言则不允许这样的操作&#xff0c;一个变量定义后类…

Qt第十七章 多线程

文章目录 多线程1. 线程概念的起源2. 三种方式创建线程3. 启动线程前的准备工作4. 启动线程/退出线程5. 操作运行中的线程6. 为每个线程提供独立数据7.子线程不能操作ui解决方案 多线程 1. 线程概念的起源 单核CPU 早期还没有线程的概念&#xff0c;如何保证2个进程同时进行呢…

BaseCTF 高校联合新生赛Week1(web)

目录 HTTP 是什么呀 喵喵喵•&#xfecc;•​编辑 md5绕过欸 A Dark Room upload Aura 酱的礼物 HTTP 是什么呀 url转义&#xff1a; 是将URL中的特殊字符转换为有效的ASCII字符格式的过程&#xff0c;以确保URL的正确解析和传输。这个过程涉及到将非ASCII字符替换为“%h…

【论文阅读】通用的语义-几何表征的机器人操作

文章目录 1. 【2023CoRL】A Universal Semantic-Geometric Representation for Robotic Manipulation针对痛点和贡献引言模型框架思考不足之处 2. Leveraging Locality to Boost Sample Efficiency in Robotic Manipulation摘要和结论引言模型框架实验思考不足之处 1. 【2023Co…

哈希表的查找、插入及删除——217、633、349、128、202、500,290、532、205(五简四中)

217. 存在重复元素&#xff08;简单&#xff09; 给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 &#xff0c;返回 true &#xff1b;如果数组中每个元素互不相同&#xff0c;返回 false 。 解法一、哈希 无则加入&#xff0c;有则代表重复&#xff0c;返回true …

Vue自定义横向轮播图

目录 前言代码效果演示详细代码实现思路轮播图实现代码组件使用代码前言 汇总一个最近写出来的效果,最新的设计稿里面要求实现一个轮播图,原本使用的Element-UI提供的轮播图不是很适配,所以选择自定义一个使用。文中附带代码实际效果演示视频。 大致需求就是:一行10个d…

敲桌子游戏

题目 在饭局上&#xff0c;会玩一种敲桌子的游戏&#xff0c;从1报数到100&#xff0c;如果报到个位含有7&#xff0c;或者十位含有7&#xff0c;或者7的倍数的数字&#xff0c;则报数人不能报出该数字&#xff0c;而是敲桌子代替。如果违反了规则&#xff0c;则进行一定的惩罚…

【python】逐步回归(多元线性回归模型中的应用)

文章目录 前言一、逐步回归1. 前进法&#xff08;Forward Selection&#xff09;2. 后退法&#xff08;Backward Elimination&#xff09;3. 逐步回归法&#xff08;Stepwise Regression&#xff09; 二、示例三、代码实现----python 前言 Matlab中逐步回归的实现可以使用 Mat…

流量分析-Windows

目录 介绍步骤 介绍 1、Medusa工具是通过并行登陆暴力破解的方法&#xff0c;尝试获取远程验证服务访问权限&#xff0c;它支持AFP, CVS, FTP, HTTP, IMAP, MS-SQL, MySQL, NCP (NetWare),NNTP, PcAnywhere, POP3, PostgreSQL, rexec, rlogin, rsh, SMB, SMTP(AUTH/VRFY), SNM…

【Windows下Oracle 11G 安装教程】

Windows下 Oracle 11G 安装及配置教程 引言数据库安装安装流程1.运行可执行程序2.取消安装更新配置3.安装及配置数据库4.选择系统的类别5.安装位置及全局数据库6.检查配置及设置情况7.配置对应数据库管理的密码 引言 在网上各种安装教程其实已经很多了&#xff0c;没必要再出这…

共享内存及网络通信

共享内存 ------ 最高效的进程间通信 一个内核预留的空间&#xff0c;两进程绑定同一块共享空间 避免了用户空间 到 内核空间的数据拷贝 IPC 操作流程 key值 > 申请 >读写 >关闭 >卸载 1,产生key值 函数ftok key_t ftok(const char *pathname, int proj_id);…

谷粒商城实战笔记-230-商城业务-认证服务-页面效果完成

这一节主要是完善各种页面效果。 一&#xff0c;用户名密码登录接口存放session 之前是在微博登录成功后把用户信息放入session&#xff0c;用户名密码登录成功也需要把用户信息放入session。 PostMapping(value "/login")public String login(UserLoginVo vo, R…