java每日一记 —— 第一次研究注解

注解学习的小总结

  • 1.万事开头难:什么是注解
  • 2.java的注解到底有什么用?
  • 3.元注解
    • 3.1.@Target
    • 3.2.@Retention
    • 3.3.@Documented
    • 3.4.@Inherited
    • 3.5.@Repeatable
  • 4.自定义注解使用
    • 4.1.定义注解
    • 4.2.使用注解
    • 4.3.获取注解的类容

本篇代码在jdk11中测试通过

1.在写这篇文章之前我说点废话,就在昨晚我和一位技术大佬聊天时他说到,之前有位面试官问他”spring中有多少注解“。我尼玛,反正我是不知道的,后来他给我说了有多少来着我也忘记了。。。。。😣😣😣😣
2.以前一直听说自定义注解需要反射,正好昨天我写了反射,那我就想着今天学习一下注解吧。。。。。。。我真的好无聊。。。废话连篇。。。语句不通顺。。。错别字连天。。。

1.万事开头难:什么是注解

1.定义:Java中的注解是一种元数据,可以被插入到源文件中,但并不会影响程序的实际逻辑。注解可以在编译时或运行时被读取和处理。它可以用于生成文档、执行编译时检查、跟踪代码依赖性以及执行其他形式的静态分析和代码理解任务

这个定义我也看不懂,这到底是TM什么东西????????

2.老规矩,我用生活中的案例说说,请看:

在开始之前,我想先问大家一个问题:你们有没有过这样的经历,在看一部电影的时候,突然出现一段字幕解释剧情或者人物背景?这就是一种注解,它可以帮助我们更好地理解和欣赏电影。同样,在编程语言Java中,也有这样一种机制,那就是注解

3.注解出现的位置:Java代码中的包、类型、构造方法、方法、成员变量、参数、本地变量的声明都可以用注解来修饰。注解本质上可以看作是一种特殊的标记,程序在编译或者运行时可以检测到这些标记而进行一些特殊的处理

4.关于注解的处理:博主很🥬,🥬到这一块不清楚,有兴趣的伙伴可以自行研究

5.小结一下:我们常常使用的注解,@Data、@Controller等等,这些都是注解,创建一个注解,也很简单,创建一个类,然后将class改为 @interface就是一个注解啦

2.java的注解到底有什么用?

下面这个案例是博主的理解和一些看法,就当个笑话看了。可能博主说的也不对,见笑了。。。。。

1.首先,Java注解可以帮助我们生成文档。通过在代码中添加注解,我们可以自动生成Javadoc文档,这对于团队协作和代码维护非常有用

2.其次,Java注解可以用于编译检查。例如,我们可以通过@Override注解来检查一个方法是否正确地重写了超类中的方法。这样,我们就可以在编译阶段发现并修复错误,而不是等到运行时才发现问题

3.此外,Java注解还可以用于编译时和运行时的动态处理。例如,Spring框架就大量使用了注解来进行依赖注入和切面编程。这使得我们的代码更加简洁,也更易于维护

4.最后,Java注解还可以用于追踪代码的依赖性,从而实现替代配置文件的功能。这样,我们就无需手动编辑繁琐的配置文件,而是可以直接在代码中进行设置

5.总的来说,Java注解是一个强大的工具,它可以极大地提高我们的开发效率,并且有助于我们写出更高质量的代码。我希望今天的分享能帮助大家更好地理解和利用Java注解

3.元注解

元注解有五个:@Target、@Retention、@Documented、@Inherited、@Repeatable

3.1.@Target

1.源码:

package java.lang.annotation;@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {ElementType[] value();
}

2.在 @Target 注解中有一个 ElementType 的约束,它告诉编译器,这个自定义的注解只能用于指定的类型

3.进入ElementType源码

package java.lang.annotation;public enum ElementType {// 类、接口(包括注释类型)或枚举声明TYPE,// 字段声明(包括枚举常量)FIELD,// 方法声明METHOD,// 形式参数声明PARAMETER,// 构造函数声明CONSTRUCTOR,// 局部变量声明LOCAL_VARIABLE,// 注释类型声明ANNOTATION_TYPE,// 包PACKAGE,// 类型参数声明TYPE_PARAMETER,// 类型的使用TYPE_USE,// 模块声明MODULE
}

4.说明了注解所修饰的对象范围:注解可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)

3.2.@Retention

1.源码:

package java.lang.annotation;@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {RetentionPolicy value();
}

2.这个注解是什么意思博主我也不清楚,博主真的很菜。。。。于是博主问了下gpt:

它可以控制其修饰的注解的生命周期。它可以设置注解的生命周期为SOURCE、CLASS或RUNTIME,其中SOURCE表示注解只存在于源码中,不会被编译进字节码;CLASS表示注解会被编译进字节码,但在运行时不可见;RUNTIME则表示注解不仅会被编译进字节码,而且在运行时也可以访问到。通过设置不同的生命周期,我们可以控制注解在何时何地可用

3.看了gpt的解释,恍然大悟,这和Lombok不是差不多的吗?在Lombok注解中我们常用的@Data注解不就是通过注解在编译时自动生成一部分代码,让源码看起来更简洁,字节码却很强大。。。好吧今天我学到了。。。。

4.我们看看约束的源码:

package java.lang.annotation;public enum RetentionPolicy {// 注释将被编译器丢弃SOURCE,// 注释将由编译器记录在类文件中,但运行时不需要被虚拟机保留。// 这是默认值行为。// 注释将被编译器丢弃CLASS,// 注释将由编译器记录在类文件中,并在运行时由VM保留,因此它们可能被反射地读取RUNTIME
}

5.这里不多解释了,这个注解在开发中真的很少用,用数学的角度看 limit x->0

3.3.@Documented

1.源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

2.源码什么都没:博主直接说他有什么用吧!!!!!它用来标记一个注解应该被包含在JavaDoc中。当我们在Java类或方法上使用了这个注解时,它的信息就会出现在对应的JavaDoc中,这对于其他人阅读和理解我们的代码非常有帮助

3.4.@Inherited

1.源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

2.这怎么又没成员?看了几篇博客加上结合自己的理解总结一下:它允许子类继承父类上的注解。当我们在一个类上使用了@Inherited修饰的注解,并且该类有一个子类,则子类也会自动继承这个注解

3.通俗的说法:

  • 首先,让我们从一个故事开始。想象一下,你在编写一段代码时,突然发现了一个错误,你需要修复它。然而,当你试图修改这段代码时,却发现同样的错误也出现在其他几个类中。这时,你会怎么做呢?可能你会逐一修改这些类,但这无疑是一项繁琐且耗时的工作。而这就是我们引入“@Inherited注解”的原因。

  • 那么,“@Inherited注解”究竟是什么呢?简单来说,它是一个允许子类继承父类中的元数据的注解。这意味着,如果你在一个父类上添加了“@Inherited注解”,那么所有继承自这个父类的子类都将自动获得这个注解。

3.5.@Repeatable

1.源码

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {Class<? extends Annotation> value();
}

2.说白了它就是允许一个注解可以被使用一次或者多次

3.举个案例:

在我们开发一款音乐播放器时,可能需要处理各种类型的音乐文件。我们可以为每种文件类型创建一个单独的注解,如@MP3、@WAV等。但是,如果一首歌曲包含了多种格式的音频文件,我们就需要在一个类上多次应用这些注解。这就是@Repeatable注解发挥作用的地方

4.小结一下:@Repeatable注解是一个强大的工具,可以帮助我们更好地管理和组织代码。我希望我的分享能帮助大家更好地理解和使用这个特性

4.自定义注解使用

博主从4个方面说起,类,构造,方法,成员属性

4.1.定义注解

1.定义在类上使用的注解

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;// 定义可以被文档工具文档化
@Documented
// 声明周期为runtime,运行时可以通过反射拿到
@Retention(RetentionPolicy.RUNTIME)
// 注解修饰范围为类、接口、枚举
@Target(ElementType.TYPE)
public @interface AndyClassAnnotation {// 默认名称String name() default "defaultAndyClass";// 版本号String version() default "1.0.0";
}

2.定义在构造器上使用的注解

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;// 定义可以被文档工具文档化
@Documented
//注解修饰范围为构造
@Target(ElementType.CONSTRUCTOR)
// 声明周期为runtime,运行时可以通过反射拿到
@Retention(RetentionPolicy.RUNTIME)
public @interface AndyConstructorAnnotation {// 构造器名称String constructorName() default "";// 备注String remark() default "构造器";
}

3.定义在方法上使用的注解

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;// 定义可以被文档工具文档化
@Documented
// 声明周期为runtime,运行时可以通过反射拿到
@Retention(RetentionPolicy.RUNTIME)
// 注解修饰范围为方法
@Target(ElementType.METHOD)
public @interface AndyMethodAnnotation {// 名称String name() default "defaultAndyMethod";
}

4.定义在成员属性上使用的注解

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;// 定义可以被文档工具文档化
@Documented
// 修饰范围成员
@Target(ElementType.FIELD)
// 声明周期为runtime,运行时可以通过反射拿到
@Retention(RetentionPolicy.RUNTIME)
public @interface AndyFieldAnnotation {// keyString name() default "defaultAndyName";// valueString value() default "defaultAndyValue";
}

4.2.使用注解

1.创建一个类

package com.andy.zhu_jie.test;import com.andy.zhu_jie.ding_yi.AndyClassAnnotation;
import com.andy.zhu_jie.ding_yi.AndyFieldAnnotation;
import com.andy.zhu_jie.ding_yi.AndyMethodAnnotation;/*** @author Andy* @version 0.0.1* @since 2023-11-19 13:15*/
@AndyClassAnnotation(name = "TestClassAnnotation", version = "2.0.0")
public class TestClassAnnotation {@AndyFieldAnnotation(name = "name", value = "这是一个测试")private String name;// @AndyConstructorAnnotation(constructorName ="这是构造器")// public TestClassAnnotation(String name) {//     this.name = name;// }public String getName() {return name;}public void setName(String name) {this.name = name;}@AndyMethodAnnotation(name = "sayHello")public void sayHello(){System.out.println("你好注解");}
}

4.3.获取注解的类容

1.获取类注解

public class TestMain {private static TestClassAnnotation testClassAnnotation = new TestClassAnnotation();public static void main(String[] args) {Class<?> clazz = testClassAnnotation.getClass();// 因为注解是作用于类上面的,所以可以通过isAnnotationPresent来判断是否是一个具有指定注解的类if (clazz.isAnnotationPresent(AndyClassAnnotation.class)) {System.out.println("获取到了类注解");// 通过getAnnotation可以获取注解对象AndyClassAnnotation annotation = clazz.getAnnotation(AndyClassAnnotation.class);if (null != annotation) {System.out.println("类名称 = " + annotation.name());System.out.println("类版本 = " + annotation.version());} else {System.out.println("没有获取到注解");}} else {System.out.println("这是一个类注解");}}
}

2.完整代码

package com.andy.zhu_jie.test;import com.andy.zhu_jie.ding_yi.AndyClassAnnotation;
import com.andy.zhu_jie.ding_yi.AndyConstructorAnnotation;
import com.andy.zhu_jie.ding_yi.AndyFieldAnnotation;
import com.andy.zhu_jie.ding_yi.AndyMethodAnnotation;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;/*** @author Andy* @version 0.0.1* @since 2023-11-19 13:18*/
public class TestMain {public static void main(String[] args) throws ClassNotFoundException {Class<?> clazz = Class.forName("com.andy.zhu_jie.test.TestClassAnnotation");System.out.println("===类注解解析===");printClass(clazz);System.out.println("===成员变量注解解析===");printField(clazz);System.out.println("===成员方法注解解析===");printMethod(clazz);System.out.println("===构造器注解解析===");printConstructor(clazz);}/*** 打印类的注解*/private static void printClass(Class<?> clazz) throws ClassNotFoundException {// 判断是否有AuthorAnnotation注解if (clazz.isAnnotationPresent(AndyClassAnnotation.class)) {// 获取AuthorAnnotation类型的注解AndyClassAnnotation annotation = clazz.getAnnotation(AndyClassAnnotation.class);System.out.println(annotation.name() + "\t" + annotation.version());}}/*** 打印成员变量的注解*/private static void printField(Class<?> clazz) throws ClassNotFoundException {Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {if (field.isAnnotationPresent(AndyFieldAnnotation.class)) {AndyFieldAnnotation annotation = field.getAnnotation(AndyFieldAnnotation.class);System.out.println(annotation.name() + "\t" + annotation.value());}}}/*** 打印成员变量的注解*/private static void printMethod(Class<?> clazz) throws ClassNotFoundException {Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {if (method.isAnnotationPresent(AndyMethodAnnotation.class)) {AndyMethodAnnotation annotation = method.getAnnotation(AndyMethodAnnotation.class);System.out.println(annotation.name() + "\t");}}}/*** 打印成员变量的注解*/private static void printConstructor(Class<?> clazz) throws ClassNotFoundException {Constructor<?>[] constructors = clazz.getDeclaredConstructors();for (Constructor<?> constructor : constructors) {if (constructor.isAnnotationPresent(AndyConstructorAnnotation.class)) {AndyConstructorAnnotation annotation = constructor.getAnnotation(AndyConstructorAnnotation.class);System.out.println(annotation.constructorName() + "\t" + annotation.remark());}}System.out.println("无");}
}

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

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

相关文章

在MySQL中创建新的数据库,可以使用命令,也可以通过MySQL工作台

摘要:在本教程中,你将学习如何使用MySQL CREATE DATABASE语句在MySQL数据库服务器上创建新数据库。 MySQL CREATE DATABASE语句简介 要在MySQL中创建新数据库,可以使用CREATE DATABASE语句。以下说明了CREATE DATABASE语句的基本语法: CREATE DATABASE [IF NOT EXISTS] …

超详细vue3选项式父子组件传值

一、问题背景 最近遇到了一个情景&#xff1a; 子组件干完事情&#xff0c;需要对父组件的变量进行更新&#xff0c;因为父组件将该变量传递给子组件&#xff0c;但是不会双向绑定&#xff0c;这时候我们就需要传值或者触发回调去解决这个问题 我们将分为两个部分 1.父组件传…

力扣hot100 两数之和 哈希表

&#x1f468;‍&#x1f3eb; 力扣 两数之和 &#x1f60b; 思路 在一个数组中如何快速找到某一个数的互补数&#xff1a;哈希表 O(1)实现⭐ AC code class Solution {public int[] twoSum(int[] nums, int target){HashMap<Integer, Integer> map new HashMap<&g…

【机器学习12】集成学习

1 集成学习分类 1.1 Boosting 训练基分类器时采用串行的方式&#xff0c; 各个基分类器之间有依赖。每一层在训练的时候&#xff0c; 对前一层基分类器分错的样本&#xff0c; 给予更高的权重。 测试时&#xff0c; 根据各层分类器的结果的加权得到最终结果。 1.2 Bagging …

基于世界杯算法优化概率神经网络PNN的分类预测 - 附代码

基于世界杯算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于世界杯算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于世界杯优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络…

Docker 笔记(二)--镜像

Docker 笔记&#xff08;二&#xff09;–镜像 记录Docker 安装操作记录&#xff0c;便于查询。 参考 链接: Docker 入门到实战教程(三)镜像和容器链接: docker中daemon.json各配置详解链接: docker容器/etc/docker/daemon.json配置文件详解链接: docker官方文档 环境 Cen…

python+appium+pytest自动化测试-参数化设置

来自APP Android端自动化测试初学者的笔记&#xff0c;写的不对的地方大家多多指教哦。&#xff08;所有内容均以微博V10.11.2版本作为例子&#xff09; 在自动化测试用例执行过程中&#xff0c;经常出现执行相同的用例&#xff0c;但传入不同的参数&#xff0c;导致我们需要重…

IntelliJ IDEA 2023 v2023.2.5

IntelliJ IDEA 2023是一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;为开发人员提供了许多特色功能&#xff0c;以下是其特色介绍&#xff1a; 新增语言支持&#xff1a;IntelliJ IDEA 2023新增对多种编程语言的支持&#xff0c;包括Kotlin、TypeScript、…

基于寄生捕食算法优化概率神经网络PNN的分类预测 - 附代码

基于寄生捕食算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于寄生捕食算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于寄生捕食优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

Python正则表达式学习笔记(入门)

1. 介绍 正则表达式是一种强大的模式匹配工具&#xff0c;用于处理文本数据。在Python中&#xff0c;我们使用re模块来操作正则表达式。 2. 基本语法 建议先看 "5. re模块函数"了解search和match的区别"和 2.3 特殊字符转义"了解如何应对特殊符号 2.1 字…

MATLAB与Excel的数据交互

准备阶段 clear all % 添加Excel函数 try Excel=actxGetRunningServer(Excel.Application); catch Excel=actxserver(Excel.application); end % 设置Excel可见 Excel.visible=1; 插入数据 % % 激活eSheet1 % eSheet1.Activate; % 或者 % Activate(eSheet1); % % 打开…

js:react使用zustand实现状态管理

文档 https://www.npmjs.com/package/zustandhttps://github.com/pmndrs/zustandhttps://docs.pmnd.rs/zustand/getting-started/introduction 安装 npm install zustand示例 定义store store/index.js import { create } from "zustand";export const useCount…

【漏洞复现】浙大恩特CRM文件上传0day

漏洞描述 浙大恩特客户资源管理系统任意文件上传漏洞 免责声明 技术文章仅供参考,任何个人和组织使用网络应当遵守宪法法律,遵守公共秩序,尊重社会公德,不得利用网络从事危害国家安全、荣誉和利益,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用…

C 语言 gets()和puts()

C 语言 gets()和puts() gets()和puts()在头文件stdio.h中声明。这两个函数用于字符串的输入/输出操作。 C gets()函数 gets()函数使用户可以输入一些字符&#xff0c;然后按Enter键。 用户输入的所有字符都存储在字符数组中。 空字符将添加到数组以使其成为字符串。 gets()允…

Rust开发——切片(slice)类型

1、什么是切片 在 Rust 中&#xff0c;切片&#xff08;slice&#xff09;是一种基本类型和序列类型。在 Rust 官方文档中&#xff0c;切片被定义为“对连续序列的动态大小视图”。 但在rust的Github 源码中切片被定义如下&#xff1a; 切片是对一块内存的视图&#xff0c;表…

【草料】uni-app ts vue 小程序 如何如何通过草料生成对应的模块化二维码

一、查看uni-app项目 1、找到路径 可以看到项目从 src-race-pages-group 这个使我们目标的查询页面 下面我们将这个路径copy到草料内 2、找到进入页面入参 一般我们都会选择 onload() 函数下的入参 这里我们参数的是 id 二、草料 建议看完这里的教程文档 十分清晰&#xff01…

【Linux】C文件系统详解(三)——如何理解缓冲区以及自主封装一个文件接口

文章目录 如何理解缓冲区现象概念:文件缓冲区为什么要有缓冲区缓冲区在哪里 自己封装一个简单的文件接口自主封装目标 代码关于缓冲区强制刷新内核 关于字符串格式化函数printf和scanf函数 如何理解缓冲区 以前写过一个进度条, 有一个输出缓冲区->这个缓冲区在哪里,为什么要…

hyperledger fabric2.4测试网络添加组织数量

!!!修改内容比较繁琐,预期未来提供模板修改 修改初始配置文件,初始添加3个组织 organizations文件夹 /cryptogen文件夹下创建文件crypto-config-org3.yaml,内容如下: PeerOrgs:# ---------------------------------------------------------------------------# Org3# ----…

酷柚易汛ERP - 序列号盘点操作指南

1、应用场景 将系统中开启序列号的商品数量与与实际存放的数量进行对比。 2、主要操作 2.1 录入序列号 打开【盘点】-【序列号盘点】&#xff0c;新增序列号盘点单&#xff0c;点击【SN】按钮&#xff0c;在弹框中输入序列号。 支持扫描枪录入序列号支持复制粘贴序列号录入…

Java(二)(String的常见方法,ArrayList的常见方法)

String 创建string对象 package Helloworld;public class dome1 {public static void main(String[] args) {// 1.直接双引号得到字符串对象,封装字符串对象String name "lihao";System.out.println(name);// 2. new String 创建字符串对象,并调用构造器初始化字符…