注解【元数据,自定义注解等概念详解】(超简单的好吧)

注解的理解与使用

  • 注解的释义
  • 元数据的含义
  • 基础阶段常见的注解
  • 注解的作用(包括但不限于)
  • 教你读懂注解内部代码内容
    • 五种元注解
    • 尝试解读简单注解
    • ==我当时的疑惑点==
  • 自定义注解
    • 自定义注解举例
  • 注解的原理
  • 总结

在这里插入图片描述

注解的释义

我们都知道注释是拿来给程序员看的,而注解就是给程序(或者说JVM)看的。

注解(Annotation)是代码级别的说明,它是JDK 1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。注解是Java语言中的一种元数据形式,它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明。

在这里插入图片描述

元数据的含义

在Java中,元数据的含义是指描述Java类、接口、字段和方法等元素的数据。这些数据提供了关于Java程序元素的额外信息,可以用于反射、注解处理、代码生成等场景。通过元数据,我们可以在运行时获取和操作程序元素的属性、注解等信息,从而实现更灵活和动态的编程能力。

基础阶段常见的注解

我们在基础阶段常见的注解并没有多少,很少用到复杂注解,

注解Value
@Override(重写或者覆盖)一般放在方法前面,表示方法在子类中重写了超类中的方法
@Deprecated可放在类、方法或字段前面,表示一个类、方法或字段已经过时了,不应该再使用
@SuppressWarnings一般放在程序代码靠前位置,抑制编译器产生的警告,这个注解后面有大括号是可以传参的,一般图方便就是写个“all”
@Native一般放在方法前面,指示一个方法是native方法,即由本地代码实现的方法
@Test一般用于测试,可以不用启动整个项目就能调用部分代码

注解的作用(包括但不限于)

标记检查

注解可以用来标记一些需要被检查的代码,以便进行静态检查或动态检查。

代码生成

注解可以被用来生成代码,如JUnit注解可以根据测试方法定义生成测试用例。

生成文档

特定的注解可以用来生成对应文档,例子是在注释里的注解

拿最后一个举个例子
编写一个演示类

package budiu.budiu;

/**
 * 这是一个名字为DocDemo的类
 *
 * @Author:罗不丢
 * @Version:1.0
 */

public class DocDemo {
    /**
     * @param  name
     * @return java.lang.String
     **/
    public String play (String name){
        return name+"正在玩";
    }
}

注意编码格式别搞错,有中文的把UTF-8换成GBK
在这里插入图片描述

用javadoc命令生成文档
在这里插入图片描述

就会生成一堆的前端文件,可以当做文档查看
在这里插入图片描述

教你读懂注解内部代码内容

在想要了解注解的内部代码,我们要先了解五种元注解(元注解的意思是注解的最基本组成部分,任何注解都要由它们组成)

五种元注解

@Retention:
它只有一个参数:RetentionPolicy,用于指定注解的生命周期。
这个参数有三个可能的值:
RetentionPolicy.SOURCE(注解仅在源代码中存在,编译时会被丢弃),
RetentionPolicy.CLASS(注解在编译时会被保留,在JVM中运行时不可见)
RetentionPolicy.RUNTIME(注解在运行时还会存在,可以通过反射机制读取它的信息)。

@Target:
它有一个参数:ElementType,用于指定注解可以应用到的Java元素类型。
例如,方法可以被注解,字段可以被注解,甚至注解本身也可以被注解。
ElementType包含多种可能的值,如ElementType.METHODElementType.FIELDElementType.ANNOTATION_TYPE等。

@Documented:
这个元注解没有参数。它的作用是表示使用该注解的注解信息能够被javadoc或类似工具文档化。

@Inherited:
这个元注解也没有参数。表示被它修饰的注解具有继承性,即如果一个类声明了被@Inherited修饰的注解,那么它的子类也将具有这个注解。
注意:不是注解继承父注解,而是子类继承父类里的注解。

@Repeatable:
这个元注解是Java 1.8引入的,它表示一个注解可以被重复使用在一个声明上。它有一个参数,这个参数是用来定义该注解的“容器”注解类型,用于存储重复注解的数据。(还没怎么了解过)

尝试解读简单注解

这里以最简单的@Override注解(JDK1.8版本)为引入

/*
 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package java.lang;

import java.lang.annotation.*;

/**
 * Indicates that a method declaration is intended to override a
 * method declaration in a supertype. If a method is annotated with
 * this annotation type compilers are required to generate an error
 * message unless at least one of the following conditions hold:
 * 指示方法声明旨在重写
 * 超类型中的方法声明。如果方法被注释
 *需要此注释类型编译器才能生成错误
 *消息,除非至少满足以下条件之一:
 *
 *
 * <ul><li>
 * The method does override or implement a method declared in a
 * supertype.
 * 该方法会重写或实现在
 * 超类型。
 * </li><li>
 * The method has a signature that is override-equivalent to that of
 * any public method declared in {@linkplain Object}.
 * 该方法具有覆盖等效于
 * 在 {@linkplain Object} 中声明的任何公共方法。
 * </li></ul>
 *
 * @author  Peter von der Ah&eacute;
 * @author  Joshua Bloch
 * @jls 9.6.1.4 @Override
 * @since 1.5
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

除去注释后,代码并不算长,我们只需要了解三行,

@Target(ElementType.METHOD):
这是一个元注解,它用来指明Override注解可以用在什么地方。在这个例子中,它表示Override只能用在方法上。ElementType.METHOD表示这个注解的目标是方法。

@Retention(RetentionPolicy.SOURCE):
这是另一个元注解,用来指明注解的保留策略。这里指定的是RetentionPolicy.SOURCE,意味着这个注解只保留在源代码中,编译成.class文件时它将被丢弃。也就是说,这个注解在运行时是不可见的。

public @interface Override:
这定义了一个名为Override的注解接口。@interface是用来声明一个注解的关键字。这个接口是公开的(public),意味着它可以被任何人访问。

再试着解读一个


/**
 * Indicates that the named compiler warnings should be suppressed in the
 * annotated element (and in all program elements contained in the annotated
 * element).  Note that the set of warnings suppressed in a given element is
 * a superset of the warnings suppressed in all containing elements.  For
 * example, if you annotate a class to suppress one warning and annotate a
 * method to suppress another, both warnings will be suppressed in the method.


 * 表示应在
 * 带注释的元素(以及包含在带注释的
 * 元素)。 请注意,给定元素中禁止显示的警告集是
 * 在所有包含元素中禁止显示的警告的超集。 为
 * 例如,如果您对一个类进行注释以禁止显示一个警告并注释一个警告
 * 方法来抑制另一个,两个警告都会在该方法中被禁止。
 *
 *
 * <p>As a matter of style, programmers should always use this annotation
 * on the most deeply nested element where it is effective.  If you want to
 * suppress a warning in a particular method, you should annotate that
 * method rather than its class.
 *

 *作为风格问题,程序员应该始终使用此注解
 * 在最深嵌套的元素上,它有效。 如果你想
 * 在特定方法中禁止警告,您应该注释
 * 方法而不是它的类。


 * @author Josh Bloch
 * @since 1.5
 * @jls 4.8 Raw Types
 * @jls 4.12.2 Variables of Reference Type
 * @jls 5.1.9 Unchecked Conversion
 * @jls 5.5.2 Checked Casts and Unchecked Casts
 * @jls 9.6.3.5 @SuppressWarnings
 */
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    /**
     * The set of warnings that are to be suppressed by the compiler in the
     * annotated element.  Duplicate names are permitted.  The second and
     * successive occurrences of a name are ignored.  The presence of
     * unrecognized warning names is <i>not</i> an error: Compilers must
     * ignore any warning names they do not recognize.  They are, however,
     * free to emit a warning if an annotation contains an unrecognized
     * warning name.
     *
     * <p> The string {@code "unchecked"} is used to suppress
     * unchecked warnings. Compiler vendors should document the
     * additional warning names they support in conjunction with this
     * annotation type. They are encouraged to cooperate to ensure
     * that the same names work across multiple compilers.
     * @return the set of warnings to be suppressed
     */
    String[] value();
}

这个注解是Java的@SuppressWarnings注解,它的定义解释了它的功能和用法。现在,我们来详细解读一下这个注解:

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}):
这是@SuppressWarnings注解的元注解,指明了它可以用于什么类型的Java元素。具体来说,它可以用于类、字段、方法、参数、构造器和局部变量。它的作用范围非常广泛。

@Retention(RetentionPolicy.SOURCE):
这个元注解表示@SuppressWarnings注解的保留策略是SOURCE,也就是说它仅在源代码中存在,编译时会被丢弃。因此,这个注解不会影响运行时的行为。

public @interface SuppressWarnings:
这定义了名为SuppressWarnings的注解。当开发者想要抑制编译器产生的某些警告时,可以使用这个注解。

String[] value();:
这是@SuppressWarnings注解的唯一 一个元素。它是一个字符串数组,表示要抑制的警告的名称。例如,如果你想要抑制未经检查的转换警告,你可以使用"unchecked"字符串。编译器会忽略这些特定的警告。需要注意的是,这里提到编译器应该忽略它们不认识的警告名称,但是也可以自由选择在遇到不识别的警告名称时发出警告。

我当时的疑惑点

在解读SuppressWarnings注解时,为什么最后一段的大括号里就定义了一个字符串数组,一点逻辑都看不出来,要按照之前的思维来说,它怎么识别到字符串并判断抑制特定警告的,不应该有一些内部方法来完成吗?
在这里插入图片描述

其实在Java编译器中,当解析和处理Java代码时,会检查代码上的注解。当编译器遇到@SuppressWarnings注解时,它会查看注解中的value数组,这些值表示需要抑制的警告类型。

编译器内部会有一个警告名称与警告类型的映射逻辑。当编译器遇到特定的代码模式或情况时,它会生成相应的警告。当存在@SuppressWarnings注解时,编译器会检查生成的警告名称是否匹配注解中指定的名称,如果匹配,则不会将该警告显示给开发者。

需要注意的是,这个匹配和抑制逻辑是由编译器实现的,而不是由注解本身实现的。不同的编译器可能会对@SuppressWarnings注解中的警告名称有不同的处理方式,但通常都会遵循Java语言规范中定义的行为。

虽然@SuppressWarnings注解本身只是一个标记,但通过编译器的逻辑处理,它能够实现警告的抑制功能。
在这里插入图片描述

所以我们不太需要关注注解的逻辑,就单纯把它理解成一种给编译器识别的标识符号就好。

自定义注解

除了官方提供的注解,我们也可以自定义注解,并使用自定义注解。
自定义注解的一些规范:
注解定义:

注解使用@interface关键字进行定义。

元注解:

为你的自定义注解提供元注解,特别是@Target和@Retention,以明确你的注解的用途和生命周期。

成员变量:

注解中的成员变量代表注解的参数。这些成员变量只能是基本类型、String、Class、枚举类型、注解类型,或者这些类型的数组。

默认值:

为注解的成员变量提供一个默认值。

命名规范:

注解的名称应该是描述性的,并且应该使用名词。同时,为了避免混淆,建议为注解名称加上一个特定的前缀。

自定义注解举例

自定义注解的例子——@RepeatableHint。这个注解的目的是给开发者提供一个可重复的提示信息。

首先,定义 Hint 注解:
在这里插入图片描述

import java.lang.annotation.*;  
  
@Retention(RetentionPolicy.RUNTIME)  //会保留到运行时阶段
@Target(ElementType.TYPE)  //限制使用范围是类,枚举,接口
public @interface Hint {  
    String value();  
}

接着,定义 RepeatableHint 注解:

import java.lang.annotation.*;  
  
@Retention(RetentionPolicy.RUNTIME)  //会保留到运行时阶段
@Target(ElementType.TYPE)  //限制使用范围是类,枚举,接口
public @interface RepeatableHint {  
    Hint[] hints() default {};  //算是个嵌套吧,但底层仍是字符串数组
}

注意这里 RepeatableHint 注解中定义了一个名为 hints 的成员,它的类型是 Hint[],默认值为空数组。这样就可以在使用 RepeatableHint 注解时,重复使用 Hint 注解。

然后在需要的类或者接口或枚举类上使用这些注解:

@RepeatableHint(hints={
        @Hint("这是一个测试类的提示1"),
        @Hint("提示2")
})
public class TestClass {  
      
    public static void main(String[] args) {  
        // 获取TestClass的Class对象  
        Class<TestClass> testClass = TestClass.class;  
          
        // 判断TestClass是否带有RepeatableHint注解  
        if (testClass.isAnnotationPresent(RepeatableHint.class)) {  
            // 获取RepeatableHint注解对象  
            RepeatableHint repeatableHint = testClass.getAnnotation(RepeatableHint.class);  
              
            // 获取所有的Hint注解对象  
            Hint[] hints = repeatableHint.hints();  
              
            // 遍历并打印所有的提示信息  
            for (Hint hint : hints) {  
                System.out.println(hint.value());  
            }  
        }  
    }  
}

在处理这些注解时,可以通过反射获取到所有的 Hint 注解,并对其进行处理。例如,可以在程序启动时,通过解析这些注解,将提示信息打印到日志中或者进行其他处理。
在这里插入图片描述

注解的原理

注解的原理基于Java的反射机制。

注解本质:
注解本质上是一个接口,它继承了java.lang.annotation.Annotation接口。当我们定义一个注解时,实际上定义了一个新的接口。

动态代理:
当我们通过反射获取注解时,返回的对象实际上是Java运行时生成的动态代理对象。这意味着我们调用注解的方法时,实际上是在调用动态代理对象上的方法。

AnnotationInvocationHandler:
这是Java内部用于处理注解调用的一个类。当我们通过动态代理对象调用注解的方法时,最终会调用AnnotationInvocationHandlerinvoke方法。这个方法会从一个叫做memberValues的Map中索引出对应的值。

memberValues的来源:
memberValues中的数据来源于Java的常量池。这就是为什么我们可以在注解中定义一些常量,然后这些常量的值会被存储在Java的常量池中。

元注解的角色:
元注解如@Retention, @Target等,它们的作用是描述注解的特性。例如,@Retention定义了注解的生命周期,@Target定义了注解可以应用的目标。

运行时处理:
大部分注解的处理都是在运行时完成的。例如,框架可能会在运行时扫描某个特定的注解,并根据该注解的属性修改框架的行为。

总的来说,注解提供了一种元编程的方式。我们可以在不改变原有代码逻辑的情况下,通过添加注解来改变代码在编译后或者运行时的行为。而这一切都是基于Java的反射机制以及动态代理技术实现的。

总结

虽然注解在Java SE阶段用的很少,但在框架学习中,比如SpringBoot中将会成为常客,我们也会从面向对象编程逐渐转化为面向注解编程🤭🤭🤭🤭🤭。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

fopen/fwrite/fread 对UNICODE字符写入的总结

windows对fopen函数进行了升级&#xff0c;可以支持指定文件的编码格式&#xff08;ccs参数指定&#xff09;。 例如&#xff1a; FILE *fp fopen("newfile.txt", "rt, ccsUTF-8"); 当以 ccs 模式打开文件时&#xff0c;进行读写操作的数据应为 UTF-16…

湖北成人自考毕业学位申请照片要求及自拍制作方法

湖北成人自考学位申请需要上传照片是为了身份验证和学籍管理的目的。通过上传照片&#xff0c;学校可以确认申请者的身份&#xff0c;并将照片与其他申请信息进行关联。这有助于提高学校对学生的管理效率&#xff0c;确保学籍信息的准确性。同时&#xff0c;照片也用于学位证书…

公众号留言功能怎么恢复?评论功能如何开启?

为什么公众号没有留言功能&#xff1f;从2018年2月开始&#xff0c;新注册的微信公众号取消了留言功能&#xff0c;原因是为了规避一些营销号通过虚假留言骗取读者信任。不过大部分公众号运营者对TX此举感到失望&#xff0c;一方面大片的留言就像店前排队的顾客&#xff0c;能体…

项目全生命周期阶段检查单

项目全生命周期阶段检查单 1、立项阶段 2、计划阶段 3、需求阶段 4、设计阶段 5、编码集成阶段 6、测试阶段 7、交付阶段 8、结项阶段

高可用--限流熔断降级

熔断 熔断是应对微服务雪崩效应的一种链路保护机制。 场景 服务端出现问题 服务指标&#xff1a;响应时间、错误率、连续错误数等&#xff0c;超过阈值出发熔断。硬件指标&#xff1a;CPU、网络IO、内存 目的 服务端恢复需要时间、服务端需要休息避免全调用链路崩溃&…

Unity使用Visual Studio Code 调试

Unity 使用Visual Studio Code 调试C# PackageManager安装Visual Studio EditorVisual Studio Code安装Unity 插件修改Unity配置调试 PackageManager安装Visual Studio Editor 打开 Window->PackageManger卸载 Visual Studio Code Editor &#xff0c;这个已经被官方废弃安…

portraiture2024ps磨皮插件参数设置教程

ps磨皮插件一般是第三方软件&#xff0c;通过安装的方式放在ps的相关文件夹中。但也有一些插件是放置在系统软件目录的&#xff0c;不与ps文件放在一起。本文会给大家具体介绍以上两种不同的情况&#xff0c;方便大家了解ps磨皮插件放在哪个文件夹&#xff0c;ps的磨皮插件在哪…

每天一点python——day71

#每天一点Python——71 #格式化字符串在Python中&#xff0c;你可以使用格式化字符串来动态地插入变量的值、表达式的结果等到字符串中。 如图&#xff1a;xxx部分需要不断变化&#xff0c;再和原文拼接 如上图所示这是一个类似于字符串拼接的操作。 因为字符串拼接操作会产生很…

Linux:清空或删除大文件内容的5种方法

在Linux终端下处理文件时&#xff0c;有时我们想直接清空文件的内容但又不必使用任何Linux命令行编辑器 去打开这些文件。那怎样才能达到这个目的呢&#xff1f;在这篇文章中&#xff0c;我们将介绍几种借助一些实用的命令来清空文件内容的方法。 注意&#xff1a;在我们进一步…

美国政府首席信息安全官详细介绍零信任战略竞赛

如果企业想吸取教训&#xff0c;为庞大的组织快速制定零信任战略&#xff0c;他们应该看看美国联邦政府在 2024 年之前让所有机构合规的努力。 这就是被任命为联邦办公室 CISO&#xff08;首席信息安全官&#xff09; 的克里斯德鲁沙 (Chris DeRusha) 的看法。 周三&#xf…

debian10 开启rdp安装firefox,firefox 中文乱码

debian10 开启rdp安装firefox apt -y install tigervnc-standalone-server apt -y install xrdp tigervnc-standalone-server systemctl enable xrdpapt install firefox-esrmstsc连接 firefox-settings-general-fonts-advanced-Simplified Chinese

Redis(地理空间Geospatial和HyperLogLog)

Geospatial&#xff1a; Redis中的Geospatial提供了一种存储和处理地理空间数据的能力&#xff0c;这对于许多应用非常有用。以下是Redis中的Geospatial的一些作用&#xff1a; 1. 地理位置查询&#xff1a;可以存储地理位置的坐标信息&#xff0c;并且可以通过查询指定半径范…

Windows 下提取EXE文件中的图标

可以使用两种工具&#xff1a; 1 使用 IconViewer 下载地址: https://www.botproductions.com/iconview/download.html 2 使用 QuickAny2Ico 下载地址&#xff1a; Quick Any2Ico - Create icons from any source 2.1 操作步骤 样例(采用 python-3.7.9.exe 作为例子提取为…

【开源】基于Vue和SpringBoot的微信小程序的音乐平台

项目编号&#xff1a; S 055 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S055&#xff0c;文末获取源码。} 项目编号&#xff1a;S055&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示 四、核心代码4.1 查询单首…

Linux--初识和基本的指令(1)

目录 前言 0.什么是操作系统 0.1 搭建 Linux 环境 0.2搭建 Linux 环境小结 1.使用 XShell 远程登录 Linux 1.1关于 Linux 桌面 1.2下载安装 XShell 1.3查看 Linux 主机 ip 1.4XShell 下的复制粘贴 2.Linux下基本指令 2.1 pwd命令 2.2 ls命令 2.3 mkdir指令 2.4 cd…

C语言三位数求解(ZZULIOJ1076:三位数求解)

题目描述 已知xyzyzzn&#xff0c;其中n是一个正整数&#xff0c;x、y、z都是数字&#xff08;0-9&#xff09;&#xff0c;编写一个程序求出x、y、z分别代表什么数字。如果无解&#xff0c;则输出“No Answer”注意&#xff1a;xyz和yzz表示一个三位数&#xff0c;而不是表示x…

【csapp lab】lab2_bomblab

文章目录 前言实验内容phase_1phase_2phase_3phase_4phase_5phase_6secret_phase 前言 刚做了csapp lab2&#xff0c;记录一下。 我这里用的的系统环境是Ubuntu22.04&#xff0c;是64位系统&#xff0c;与用32位系统可能有所差异。 实验共包括七个阶段&#xff0c;每个阶段考…

山西电力市场日前价格预测【2023-11-20】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-11-20&#xff09;山西电力市场全天平均日前电价为255.39元/MWh。其中&#xff0c;最高日前电价为436.50元/MWh&#xff0c;预计出现在18:00。最低日前电价为21.61元/MWh&#xff0c;预计出…
最新文章