java高级:注解

2023-10-27

认识注解&自定义注解

注解和反射一样,都是用来做框架的,我们这里学习注解的目的其实是为了以后学习框架或者做框架做铺垫的。

先来认识一下什么是注解?Java注解是代码中的特殊标记,比如@Override、@Test等,作用是:让其他程序根据注解信息决定怎么执行该程序。

比如:Junit框架的@Test注解可以用在方法上,用来标记这个方法是测试方法,被@Test标记的方法能够被Junit框架执行。
再比如:@Override注解可以用在方法上,用来标记这个方法是重写方法,被@Override注解标记的方法能够被IDEA识别进行语法检查。

注解不光可以用在方法上,还可以用在类上、变量上、构造器上等位置。

上面我们说的@Test注解、@Overide注解是别人定义好给我们用的,将来如果需要自己去开发框架,就需要我们自己定义注解。

自定义注解的格式如下图所示
请添加图片描述

比如:现在我们自定义一个MyTest注解,注意新建的时候不是class了,而是Annotation

public @interface MyTest1{
    String aaa();//一定要带小括号 前面的public可以不写 默认自动帮你写了
    boolean bbb() default true;	//default true 表示默认值为true,使用时可以不赋值。
    String[] ccc();
}

定义好MyTest注解之后,我们可以使用MyTest注解在类上、方法上等位置做标记。注意使用注解时需要加@符号,如下

@MyTest1(aaa="牛魔王",ccc={"HTML","Java"})
public class AnnotationTest1{
    @MyTest1(aaa="铁扇公主",bbb=false, ccc={"Python","前端","Java"})
    public void test1(){
        
    }
}

注意:注解的属性名如果是value的话,并且只有value没有默认值,使用注解时value名称可以省略。比如现在重新定义一个MyTest2注解

public @interface MyTest2{
    String value(); //特殊属性
    int age() default 10;
}

定义好MyTest2注解后,再将@MyTest2标记在类上,此时value属性名可以省略,代码如下

@MyTest2("孙悟空") //等价于 @MyTest2(value="孙悟空")
@MyTest1(aaa="牛魔王",ccc={"HTML","Java"})
public class AnnotationTest1{
    @MyTest1(aaa="铁扇公主",bbb=false, ccc={"Python","前端","Java"})
    public void test1(){
        
    }
}

到这里关于定义注解的格式、以及使用注解的格式就学习完了。

那注解本质是什么呢?

想要搞清楚注解本质是什么东西,我们可以把注解的字节码进行反编译,给AnnotationTest1类加个main,运行一下,会使用到的注解都编译成class,再使用XJad工具对class进行反编译。经过对MyTest1注解字节码反编译我们会发现:

1.MyTest1注解本质上是接口,每一个注解接口都继承子Annotation接口
2.MyTest1注解中的属性本质上是抽象方法
3.@MyTest1实际上是作为MyTest接口的实现类对象
4.@MyTest1(aaa="孙悟空",bbb=false,ccc={"Python","前端","Java"})里面的属性值,可以通过调用aaa()、bbb()、ccc()方法获取到。 【继续往下看,再解析注解时会用到】

请添加图片描述




接下来我们还需要学习几种特殊的注解

元注解

什么是元注解?元注解是修饰注解的注解。这句话虽然有一点饶,但是非常准确。我们看一个例子

请添加图片描述

接下来分别看一下@Target注解和@Retention注解有什么作用,它们都是用来修饰Test注解的元注解

@Target是用来声明注解只能用在哪些位置,比如:类上、方法上、成员变量上等
@Retention是用来声明修饰的注解保留周期,比如:源代码时期、字节码时期、运行时期

请添加图片描述

比如我们定义MyTest3注解时,使用@Target注解属性值写成下面样子,加上@Retention则可以决定MyTest3的保留周期,比如我们经常用到的@Test就是保留到运行阶段的,可以点进源码看一下。

//声明@MyTest3注解只能用在类上和方法上
@Target({ElementType.TYPE,ElementType.METHOD})	
public @interface MyTest3{
    
}



解析注解

通过前面的学习我们能够自己定义注解,也能够把自己定义的注解标记在类上或者方法上等位置,但是总感觉有点别扭,给类、方法、变量等加上注解后,我们也没有干什么呀!!!

接下来,我们就要做点什么。我们可以通过反射技术把类上、方法上、变量上的注解对象获取出来,然后通过调用方法就可以获取注解上的属性值了。我们把获取类上、方法上、变量上等位置注解及注解属性值的过程称为解析注解

解析注解套路如下

1.如果注解在类上,先获取类的字节码对象,再获取类上的注解
2.如果注解在方法上,先获取方法对象,再获取方法上的注解
3.如果注解在成员变量上,先获取成员变量对象,再获取变量上的注解
总之:注解在谁身上,就先获取谁,再用谁获取谁身上的注解

请添加图片描述

来看一个案例,来演示解析注解的代码编写

请添加图片描述

按照需求要求一步一步完成

① 先定义一个MyTest4注解

//声明@MyTest4注解只能用在类上和方法上
@Target({ElementType.TYPE, ElementType.METHOD})
//控制使用了@MyTest4注解的代码中,@MyTest4保留到运行时期
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest4{
    String value();
    double aaa() default 100;
    String[] bbb();
}

② 定义一个类Demo

@MyTest4(value="蜘蛛侠",aaa=99.9, bbb={"至尊宝","牛马"})
public class Demo{
    @MyTest4(value="孙悟空",aaa=199.9, bbb={"紫霞","牛夫人"})
    public void test1(){

    }
}

③ 写一个测试类AnnotationTest3解析Demo类上的MyTest4注解

public class AnnotationTest3{
    @Test
    public void parseClass(){
        //1.先获取Class对象
        Class c = Demo.class;

        //2.解析Demo类上的注解
        if(c.isAnnotationPresent(MyTest4.class)){
            //获取类上的MyTest4注解
            MyTest4 myTest4 = (MyTest4)c.getDeclaredAnnotation(MyTest4.class);
            //获取MyTests4注解的属性值
            System.out.println(myTest4.value());
            System.out.println(myTest4.aaa());
            System.out.println(Arrays.toString(myTest4.bbb()));
        }
    }

    @Test
    public void parseMethods() throws NoSuchMethodException {
        //1.先获取Class对象
        Class c = Demo.class;

        //2.解析Demo类中test1方法上的注解MyTest4注解
        Method m = c.getDeclaredMethod("test1");
        if(m.isAnnotationPresent(MyTest4.class)){
            //获取方法上的MyTest4注解
            MyTest4 myTest4 = (MyTest4)m.getDeclaredAnnotation(MyTest4.class);
            //获取MyTests4注解的属性值
            System.out.println(myTest4.value());
            System.out.println(myTest4.aaa());
            System.out.println(Arrays.toString(myTest4.bbb()));
        }
    }
}

运行测试类,parseClass()的运行结果如下:

请添加图片描述

parseMethods()的运行结果如下:

请添加图片描述




注解的应用场景

关于注解的定义、使用、解析注解就已经学习完了。接下来,我们再学习一下注解的应用场景,注解是用来写框架的,比如现在我们要模拟Junit写一个测试框架,要求有@MyTest注解的方法可以被框架执行,没有@MyTest注解的方法不能被框架执行。

第一步:先定义一个MyTest注解

@Target(ElementType.METHOD)	
@Retetion(RetetionPloicy.RUNTIME)
public @interface MyTest{
    
}

第二步:写一个测试类AnnotationTest4,在类中定义几个被@MyTest注解标记的方法

public class AnnotationTest4{
    @MyTest
    public void test1(){
        System.out.println("=====test1====");
    }
    
    @MyTest
    public void test2(){
        System.out.println("=====test2====");
    }
    

    public void test3(){
        System.out.println("=====test2====");
    }
    
    public static void main(String[] args){
        AnnotationTest4 a = new AnnotationTest4();
        
        //1.先获取Class对象
        Class c = AnnotationTest4.class;
        
        //2.解析AnnotationTest4类中所有的方法对象
        Method[] methods = c.getDeclaredMethods();
        for(Method m: methods){
            //3.判断方法上是否有MyTest注解,有就执行该方法
            if(m.isAnnotationPresent(MyTest.class)){
            	m.invoke(a);
        	}
        }
    }
}

运行结果:

=====test2====
=====test1====
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java高级:注解 的相关文章

  • scikit-learn 和tensorflow 有什么区别?可以一起使用它们吗?

    对于这个问题我无法得到满意的答案 据我了解 TensorFlow是一个数值计算库 经常用于深度学习应用 而Scikit learn是一个通用机器学习框架 但它们之间的确切区别是什么 TensorFlow 的目的和功能是什么 我可以一起使用它
  • Python——捕获异常的效率[重复]

    这个问题在这里已经有答案了 可能的重复 Python 常见问题解答 异常有多快 https stackoverflow com questions 8107695 python faq how fast are exceptions 我记得
  • Django 模型字段默认基于另一个模型字段

    我使用 Django Admin 构建一个管理站点 有两张表 一张是ModelA其中有数据 另一个是ModelB里面什么也没有 如果一个模型字段b b in ModelB为None 可以显示在网页上 值为ModelA的场a b 我不知道该怎
  • Tensorflow 不分配完整的 GPU 内存

    Tensorflow 默认分配所有 GPU 内存 但我的新设置实际上只有 9588 MiB 11264 MiB 我预计大约 11 000MiB 就像我的旧设置一样 张量流信息在这里 from tensorflow python client
  • 如何使用 PyMongo 在重复键错误后继续插入

    如果我需要在 MongoDB 中插入尚不存在的文档 db stock update one document set document upsert True 将完成这项工作 如果我错了 请随时纠正我 但是 如果我有一个文档列表并想将它们全
  • 如何在JPanel中设置背景图片

    你好 我使用 JPanel 作为我的框架的容器 然后我真的想在我的面板中使用背景图片 我真的需要帮助 这是我到目前为止的代码 这是更新 请检查这里是我的代码 import java awt import javax swing import
  • 在 Linux 上的 Python 中使用受密码保护的 Excel 工作表

    问题很简单 我每周都会收到一堆受密码保护的 Excel 文件 我必须解析它们并使用 Python 将某些部分写入新文件 我得到了文件的密码 当在 Windows 上完成此操作时 处理起来很简单 我只需导入 win32com 并使用 clie
  • 在 iPython/pandas 中绘制多条线会生成多个图

    我试图了解 matplotlib 的状态机模型 但在尝试在单个图上绘制多条线时遇到错误 据我了解 以下代码应该生成包含两行的单个图 import pandas as pd import pandas io data as web aapl
  • 为什么\0在java中不同系统中打印不同的输出

    下面的代码在不同的系统中打印不同的输出 String s hello vsrd replace 0 System out println s 当我在我的系统中尝试时 Linux Ubuntu Netbeans 7 1 它打印 When I
  • Spring @Cacheable 和 @Async 注解

    我需要缓存一些异步计算的结果 具体来说 为了克服这个问题 我尝试使用 Spring 4 3 缓存和异步计算功能 作为示例 我们采用以下代码 Service class AsyncService Async Cacheable users C
  • 将列表中的 None 替换为最左边的非 none 值

    Given a None 1 2 3 None 4 None None I d like a None 1 2 3 3 4 4 4 目前我已经用以下方法强制它 def replaceNoneWithLeftmost val last Non
  • 将 JScrollPane 添加到 JFrame

    我有一个关于向 Java 框架添加组件的问题 我有一个带有两个按钮的 JPanel 和一个添加了 JTable 的 JScrollPane 我想将这两个添加到 JFrame 中 我可以将 JPanel 添加到 JFrame 或将 JScro
  • 在Python中连续解析文件

    我正在编写一个脚本 该脚本使用 HTTP 流量行解析文件 并取出域 目前仅将它们打印到屏幕上 我正在使用 httpry 将流量连续写入文件 这是我用来删除域名的脚本 usr bin python import re input open r
  • 列表过滤器内的 Java 8 lambda 列表

    示例 JSON id 1 products id 333 status Active id 222 status Inactive id 111 status Active id 2 products id 6 status Active
  • 沿轴 0 重复 scipy csr 稀疏矩阵

    我想重复 scipy csr 稀疏矩阵的行 但是当我尝试调用 numpy 的重复方法时 它只是将稀疏矩阵视为对象 并且只会将其作为 ndarray 中的对象重复 我浏览了文档 但找不到任何实用程序来重复 scipy csr 稀疏矩阵的行 我
  • 如何在Tensorflow中保存估计器以供以后使用?

    我按照教程 TF Layers 指南 构建卷积神经网络 以下是代码 https github com tensorflow tensorflow blob r1 1 tensorflow examples tutorials layers
  • Android View Canvas onDraw 未执行

    我目前正在开发一个自定义视图 它在画布上绘制一些图块 这些图块是从多个文件加载的 并将在需要时加载 它们将由 AsyncTask 加载 如果它们已经加载 它们只会被绘制在画布上 这工作正常 如果加载了这些图片 AsyncTask 就会触发v
  • MiniDFSCluster UnsatisfiedLinkError org.apache.hadoop.io.nativeio.NativeIO$Windows.access0

    做时 new MiniDFSCluster Builder config build 我得到这个异常 java lang UnsatisfiedLinkError org apache hadoop io nativeio NativeIO
  • Python 中的字符串slugification

    我正在寻找 slugify 字符串的最佳方法 蛞蝓 是什么 https stackoverflow com questions 427102 in django what is a slug 我当前的解决方案基于这个食谱 http code
  • Java 和/C++ 在多线程方面的差异

    我读过一些提示 多线程实现很大程度上取决于您正在使用的目标操作系统 操作系统最终提供了多线程能力 比如Linux有POSIX标准实现 而windows32有另一种方式 但我想知道编程语言水平的主要不同 C似乎为同步提供了更多选择 例如互斥锁

随机推荐

  • 第52节:cesium 3DTiles模型特效+选中高亮(含源码+视频)

    结果示例 完整源码
  • PAT_Basic_Level

    PAT乙级 1001 害死人不偿命的 3n 1 猜想 1002 写出这个数 1003 我要通过 1004 成绩排名 1005 继续 3n 1 猜想 1006 换个格式输出整数 1007 素数对猜想 1008 数组元素循环右移问题 1009
  • 今天已更新!Awesome AIGC与GPT加入免费镜像、相关插件、相关网页、相关项目源码等内容...

    点击上方 Python与机器智能 选择 星标 公众号 第一时间获取价值内容 目前这个文档经过好多天的收集和整理 给大家带来最全的AIGC与GPT资料大全 数百个链接和pdf 文档本身有近20页 主要包涵资源资料分享 gpt AI绘画相关技术
  • Feign远程调用的底层方法逻辑

    今天在写业务的时候 需要通过feign调用远程接口 平常只是调用就行了 没有了解到他是如何代码实现的 今天就使用debug来解开feign为什么可以远程调用的面纱 希望看本文章的同学朋友们 可以自己写一个简单的远程调用方法跟着我一起走一遍d
  • No.13 免费音乐软件推荐:轻松畅听全网音乐

    这些开源音乐软件为用户提供了丰富的音乐搜索和播放功能 让您可以享受高品质的音乐畅听体验 它们支持多种音乐平台 如网易云音乐 QQ音乐 酷狗音乐等 同时提供了自动切换播放源 精选歌单 数据同步等实用功能 选择这些项目 您将能够轻松搜索 播放和
  • C/C++ 语言实现使用LU分解求解线性方程组

    应用计算方法C语言程序 02 接应用计算方法C语言程序 01 C C 语言实现矩阵LU分解 Doolittle A 以计算方法课本例题4 6为例 设矩阵A b分别为 A 3 3 1 3 3 2 1 1 2 3 4 b 3 1 2 1 利用C
  • oracle随机数 — dbms_random

    oracle随机数 dbms random ORACLE的PL SQL提供了生成随机数和随机字符串的多种方式 罗列如下 1 小数 0 1 select dbms random value from dual more 2 指定范围内的小数
  • fseek用法:int fseek(FILE *stream, long offset, int origin);

    1 SEEK SET 从文件开头开始定位 参数必须大于0 2 SEEK CUR 从文件当前位置开始定位 参数可正可负 3 SEEK END 从文件末尾开始定位 参数必须小于0 include
  • (附源码)springboot自习室座位预约系统 毕业设计674156

    springboot自习室座位预约系统 摘要 在社会快速发展的影响下 教育事业蓬勃发展 大大增加了学校的数量 多样性 教育质量等要求 使教育的管理和运营比过去更加困难 依照这一现实为基础 设计一个快捷而又方便的自习室座位预约系统是一项十分重
  • 判断聚类 n_clusters

    目录 基本原理 代码实现 肘部法则 Elbow Method 轮廓系数 Silhouette Coefficient Gap Statistic 间隙统计量 Calinski Harabasz Index Calinski Harabasz
  • js中对new Date() 中转换字符串方法toLocaleString的使用。

    提供特定于区域设置的日期和时间格式 dateTimeFormatObj new Intl DateTimeFormat locales options dateTimeFormatObj 必需 将 DateTimeFormat 对象分配到的
  • 《C++ Primer Plus》第四章 复合类型 4.12复习题答案

    1 char actor 30 0 short bstsie 100 0 float chuck 13 0 long double dipsea 64 0 2 array
  • QT 窗口与视口(setWindow/setViewPort)的一些理解与整理

    QPainter drawRect QRectF 绘制图形传入的是世界坐标 而后经过变换矩形变为窗口坐标 最后经过窗口 视口变换变为设备坐标 其中世界坐标系和窗口坐标系都属于逻辑坐标系 设备坐标系属于物理坐标 世界坐标 窗口坐标和设备坐标
  • ffmpeg编译,ffplay播放RTSP流,音频格式为AAC-ELD

    rtspServer已经ready 音频格式为AAC ELD encoder 为libfdk aac 发现VLC和ffplay不能正常解码AAC ELD FFmpeg可以支持3钟AAC LC编码器 aac libfaac libfdk aa
  • 改变 el-dialog 的宽度

    在 el dialog 增加 customClass 且在全局 style 里 写 style 去掉scoped
  • VS2022 无法启动程序,不是有效的Win32应用程序

    如果这里确定是 exe了 那就点击生成 gt 重新生成解决方案 不要点击生成解决方案 那个没用 然后就行了
  • 登录数据库

    登录数据库 数据库 数据库是一个以某种有组织的方式存储的数据集合 理解数据库的一种最简单的办法是将其想象为一个文件柜 此文件柜是一个存放数据的物理位置 不管数据是什么以及如何组织的 数据库 database 就是保存有组织的数据的容器 通常
  • JSON.stringify()的深入用法——第2、3个参数

    第2个参数 作用 用于过滤 格式化 没有或者是null 则所有属性被序列化JSON stringify name Ben age 18 JSON stringify name Ben age 18 null name Ben age 18
  • 信息检索复习笔记

    第一讲 搜索 IR 信息检索是什么样的学科 实质上是融合了文本及多媒体检索 数据挖掘 机器学习和自然语言处理的综合学科 为什么要进行信息检索 信息过载 搜索 搜索的过程 从大规模非结构化数据 通常是文本 的集合 通常保存在计算机上 中找出满
  • java高级:注解

    目录 认识注解 自定义注解 元注解 解析注解 注解的应用场景 认识注解 自定义注解 注解和反射一样 都是用来做框架的 我们这里学习注解的目的其实是为了以后学习框架或者做框架做铺垫的 先来认识一下什么是注解 Java注解是代码中的特殊标记 比