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

news2024/11/20 7:26:01

注解的理解与使用

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

在这里插入图片描述

注解的释义

我们都知道注释是拿来给程序员看的,而注解就是给程序(或者说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.coloradmin.cn/o/1225626.html

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

相关文章

asp.net学生成绩评估系统VS开发sqlserver数据库web结构c#编程计算机网页项目

一、源码特点 asp.net 学生成绩评估系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 系统运行视频连接&#xff1a;https://www.bilibili.com/video/BV1Wz4y1A7CG/ 二、功能介绍 本系统使用Microsof…

创建谷歌账号 绕过手机验证(2023.11亲测有效)

如何成功注册谷歌账号&#xff1a;一个详细实用指南 写在最前面谷歌注册全流程环境配置切换至全英文环境 开通foxmail.com邮箱在英文环境下注册验证邮箱注册过程中的注意事项完成&#xff01;总结 写在最前面 在这个数字化迅速发展的时代&#xff0c;谷歌账号几乎成为了我们日…

【计算机网络笔记】IPv6简介

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…

二分查找算法合集

二分查找也称折半查找&#xff08;Binary Search&#xff09;&#xff0c;它是一种效率较高的查找方法。但是&#xff0c;折半查找要求线性表必须采用顺序存储结构&#xff0c;而且表中元素按关键字有序排列。 时间复杂度 O(logn) 自己写二分算法 左闭右开 左开右闭C算法&a…

机器学习笔记 - Ocr识别中的文本检测EAST网络概述

一、文本检测 文本检测简单来说就是找到图像中可以出现文本的区域。例如,请参见下图,其中在检测到的文本周围绘制了绿色边框。 在进行文本检测时,你可能会遇到两种情况 具有结构化文本的图像:这是指具有干净/均匀背景和常规字体的图像。文本大多密集,行结构正确,…

Linux shell编程学习笔记27:tputs

除了stty命令&#xff0c;我们还可以使用tput命令来更改终端的参数和功能。 1 tput 命令的功能 tput 命令的主要功能有&#xff1a;移动更改光标、更改文本显示属性&#xff08;如颜色、下划线、粗体&#xff09;&#xff0c;清除屏幕特定区域等。 2 tput 命令格式 tput [选…

使用 Python进行量化交易:前向验证分析

运行环境&#xff1a;Google Colab 1. 利用 yfinance 下载数据 import yfinance as yfticker AAPL df yf.download(ticker) df下载苹果的股票数据 df df.loc[2018-01-01:].copy()dfdf[change_tomorrow] df[Adj Close].pct_change(-1) df.change_tomorrow df.change_tom…

C++二分查找算法:查找和最小的 K 对数字

相关专题 二分查找相关题目 题目 给定两个以 非递减顺序排列 的整数数组 nums1 和 nums2 , 以及一个整数 k 。 定义一对值 (u,v)&#xff0c;其中第一个元素来自 nums1&#xff0c;第二个元素来自 nums2 。 请找到和最小的 k 个数对 (u1,v1), (u2,v2) … (uk,vk) 。 示例 1:…

【C语言的秘密】密探—深究C语言中多组输入的秘密!

场景引入&#xff1a; 你是否在刷题过程中&#xff0c;经常遇到以下场景呢&#xff1f; 场景一&#xff1a; 场景二&#xff1a; 从这些题上都能看见输入描述中提出了一条多组输入&#xff0c;那啥是多组输入&#xff1f;如何实现它呢&#xff1f; 多组输入&#xff1a;在输入…

Centos(Linux)服务器安装Dotnet8 及 常见问题解决

1. 下载dotnet8 sdk 下载 .NET 8.0 SDK (v8.0.100) - Linux x64 Binaries 拿到 dotnet-sdk-8.0.100-linux-x64.tar.gz 文件 2. 把文件上传到 /usr/local/software 目录 mkdir -p /usr/local/software/dotnet8 把文件拷贝过去 mv dotnet-sdk-8.0.100-linux-x64.tar.gz /usr/loc…

【Linux】 uptime命令使用

uptime 正常运行时间提供以下信息的单行显示。当前时间、系统运行的时间、当前登录的用户数量以及过去1、5和15分钟的系统平均负载。 语法 uptimeuptime命令 -Linux手册页 作者 由Larry Greenfield编写和迈克尔K约翰逊编写。 命令选项及作用 执行令 man uptime 执行命令结…

【linux】进行间通信——共享内存+消息队列+信号量

共享内存消息队列信号量 1.共享内存1.1共享内存的原理1.2共享内存的概念1.3接口的认识1.4实操comm.hppservice.cc &#xff08;写&#xff09;clint.cc &#xff08;读&#xff09; 1.5共享内存的总结1.6共享内存的内核结构 2.消息队列2.1原理2.2接口 3.信号量3.1信号量是什么3…

goland 远程调试 remote debug

1、远程服务器装好go环境&#xff0c;并设置国内源 linux go安装 参考&#xff1a; 如何在 Debian / Ubuntu 上安装 Go 开发环境 - 知乎 设置国内源 go env -w GOPROXYhttps://goproxy.cn,direct 2、远程服务器安装dlv git clone https://github.com/derekparker/delve.gi…

移动端表格分页uni-app

使用uni-app提供的uni-table表格 网址&#xff1a;https://uniapp.dcloud.net.cn/component/uniui/uni-table.html#%E4%BB%8B%E7%BB%8D <uni-table ref"table" :loading"loading" border stripe type"selection" emptyText"暂无更多数据…

C++ STL之string初始

我最近开了几个专栏&#xff0c;诚信互三&#xff01; > |||《算法专栏》&#xff1a;&#xff1a;刷题教程来自网站《代码随想录》。||| > |||《C专栏》&#xff1a;&#xff1a;记录我学习C的经历&#xff0c;看完你一定会有收获。||| > |||《Linux专栏》&#xff1…

2023年【陕西省安全员B证】考试报名及陕西省安全员B证模拟试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年陕西省安全员B证考试报名为正在备考陕西省安全员B证操作证的学员准备的理论考试专题&#xff0c;每个月更新的陕西省安全员B证模拟试题祝您顺利通过陕西省安全员B证考试。 1、【多选题】《陕西省建设工程质量和…

【计算机组成原理】知识点巩固 - 存储器概述

目录 1、存储器分类 1.1、按存储介质分类 1.2、按存取方式分类 1.3、按信息的可改写性分类 1.4、按信息的可保存性分类 1.5、按功能和存取速度分类 2、存储器技术指标 2.1、存储容量 2.2、存取速度 3、存储系统层次结构 4、主存的基本结构 5、主存中数据的存放 5…

基于SSM+Vue的鲜花销售系统/网上花店系统

基于SSM的鲜花销售系统/网上花店系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringMyBatisSpringMVC工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 管理员界面 摘要 鲜花销售系统是一个基于SSM&#xff08;Spring …

springboot项目中没有识别到yml文件解决办法

springboot项目中没有识别到yml文件解决办法 ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传] 1、这个意思就是没有配置数据库的数据源路径。所以需要配置数据源&#xff0c;比如mysql的驱动和路径。检查是否在properties或者yml文件中是否已经配置好。…

75基于matlab的模拟退火算法优化TSP(SA-TSP),最优路径动态寻优,输出最优路径值、路径曲线、迭代曲线。

基于matlab的模拟退火算法优化TSP(SA-TSP)&#xff0c;最优路径动态寻优&#xff0c;输出最优路径值、路径曲线、迭代曲线。数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 75matlab模拟退火算法TSP问题 (xiaohongshu.com)