Java中常见错误-Java中注解是否可以继承

Java中注解是否可以继承

      • @Inherited
        • 基本概念
        • 使用场景
        • 注意事项
      • 实体类
      • 自定义注解
      • 测试方法
      • 运行结果
        • 使用@Inherited
        • 不使用@Inherited
      • 结论

在解决这个问题之前需要先了解一下@Inherited

@Inherited

基本概念

@Inherited是Java中的一个元注解,位于java.lang.annotation包内,它用于修饰自定义注解表明这个自定义注解具有继承性。这意味着,如果一个类应用了带有@Inherited的注解,那么它的子类在不显式添加这个注解的情况下,也会被视为拥有这个注解。然而,重要的是要理解**@Inherited的继承特性仅局限于类级别的注解,并不适用于方法、字段、构造器等成员级别的注解**。

使用场景
  • 标记接口实现:如果你定义了一套标记接口,希望实现这些接口的类自动具有某种特征或标记,可以创建一个带有@Inherited的注解来实现这一需求。
  • 框架配置:在构建框架或库时,可能需要定义一些配置注解来指导框架如何处理特定类。使用@Inherited可以让这些配置自动应用到所有子类,减少重复配置
注意事项
  • 不改变运行时行为:@Inherited仅影响编译时反射时对类是否有特定注解的判断,并不直接影响程序的运行时行为
  • 成员注解不适用:@Inherited仅对类级别的注解有效方法、字段等成员的注解即使父类有,子类也不会自动继承
  • 反射获取:即使注解是继承的,使用反射API(如Class.getAnnotation())直接在子类上获取注解时,如果没有在子类上显式声明,可能会得到null。这时可以使用Class.getDeclaredAnnotation()框架提供的工具方法(如Spring的AnnotatedElementUtils.findMergedAnnotation())来查找包括继承在内的注解

由上面可知,有无@Inherited会影响到类级别的注解是否有效,下面按照有无@Inherited注解进行分析

实体类

@MyAnnotation(value = "Class")
@Slf4j
public class Animal {
    @MyAnnotation(value = "Method")
    public void foo() {
    }
    @MyAnnotation(value = "Method")
    public void bar() {
    }
}

@Slf4j
public class Pig extends Animal {
    @Override
    public void foo() {
    }
}

自定义注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited   // 有无,决定着类级别注解可以继承
public @interface MyAnnotation {
    String value();
}

测试方法

@Slf4j
public class Main {
    public static void main(String[] args) throws NoSuchMethodException {
        wrong();
        right();
    }

    /**
     * 获取 MyAnnotation 的 value 属性值,如果注解不存在则返回空字符串。
     * @param annotation
     * @return
     */
    private static String getAnnotationValue(MyAnnotation annotation) {
        if (annotation == null) return "";
        return annotation.value();
    }

    public static void wrong() throws NoSuchMethodException {
        Animal animal = new Animal();
        log.info("AnimalClass:{}", getAnnotationValue(animal.getClass().getAnnotation(MyAnnotation.class)));
        log.info("AnimalMethod:{}", getAnnotationValue(animal.getClass().getMethod("foo").getAnnotation(MyAnnotation.class)));


        Pig pig = new Pig();
        log.info("PigClass:{}", getAnnotationValue(pig.getClass().getAnnotation(MyAnnotation.class)));
        System.out.println("重写父类的方法");
        log.info("PigMethod1:{}", getAnnotationValue(pig.getClass().getMethod("foo").getAnnotation(MyAnnotation.class)));
        System.out.println("继承父类的方法");
        log.info("PigMethod2:{}", getAnnotationValue(pig.getClass().getMethod("bar").getAnnotation(MyAnnotation.class)));


    }

    public static void right() throws NoSuchMethodException {
        Animal animal = new Animal();
        log.info("AnimalClass:{}", getAnnotationValue(animal.getClass().getAnnotation(MyAnnotation.class)));
        log.info("AnimalMethod:{}", getAnnotationValue(animal.getClass().getMethod("foo").getAnnotation(MyAnnotation.class)));

        Pig pig = new Pig();
        log.info("PigClass:{}", getAnnotationValue(AnnotatedElementUtils.findMergedAnnotation(pig.getClass(), MyAnnotation.class)));
        System.out.println("重写父类的方法");
        log.info("PigMethod1:{}", getAnnotationValue(AnnotatedElementUtils.findMergedAnnotation(pig.getClass().getMethod("foo"), MyAnnotation.class)));
        System.out.println("继承父类的方法");
        log.info("PigMethod2:{}", getAnnotationValue(AnnotatedElementUtils.findMergedAnnotation(pig.getClass().getMethod("foo"), MyAnnotation.class)));
    }
}

运行结果

使用@Inherited

17:08:16.895 [main] INFO com.kdz.annotationinheritance.Main - AnimalClass:Class //肯定可以看到
17:08:16.897 [main] INFO com.kdz.annotationinheritance.Main - AnimalMethod:Method //肯定可以看到
17:08:16.897 [main] INFO com.kdz.annotationinheritance.Main - PigClass:Class //由于使用了@Inherited注解,可以显示地看到注解
重写父类的方法
17:08:16.897 [main] INFO com.kdz.annotationinheritance.Main - PigMethod1: //子类重写了该方法而没有保留注解,直接通过反射获取时找不到注解
继承父类的方法
17:08:16.898 [main] INFO com.kdz.annotationinheritance.Main - PigMethod2:Method //子类继承了该方法,直接通过反射获取时找到注解
17:08:16.898 [main] INFO com.kdz.annotationinheritance.Main - AnimalClass:Class


17:08:16.898 [main] INFO com.kdz.annotationinheritance.Main - AnimalMethod:Method
17:08:16.952 [main] INFO com.kdz.annotationinheritance.Main - PigClass:Class
重写父类的方法
17:08:16.952 [main] INFO com.kdz.annotationinheritance.Main - PigMethod1:Method
继承父类的方法
17:08:16.952 [main] INFO com.kdz.annotationinheritance.Main - PigMethod2:Method

在这里插入图片描述

不使用@Inherited

注释掉@Inherited

在这里插入图片描述

17:11:47.786 [main] INFO com.kdz.annotationinheritance.Main - AnimalClass:Class //肯定可以看到
17:11:47.788 [main] INFO com.kdz.annotationinheritance.Main - AnimalMethod:Method //肯定可以看到
17:11:47.788 [main] INFO com.kdz.annotationinheritance.Main - PigClass:
重写父类的方法
17:11:47.788 [main] INFO com.kdz.annotationinheritance.Main - PigMethod1: //由于没有使用@Inherited注解,所以无法看到
继承父类的方法
17:11:47.788 [main] INFO com.kdz.annotationinheritance.Main - PigMethod2:Method //子类继承了该方法,直接通过反射获取时找到注解

17:11:47.788 [main] INFO com.kdz.annotationinheritance.Main - AnimalClass:Class
17:11:47.788 [main] INFO com.kdz.annotationinheritance.Main - AnimalMethod:Method
17:11:47.839 [main] INFO com.kdz.annotationinheritance.Main - PigClass:Class
重写父类的方法
17:11:47.840 [main] INFO com.kdz.annotationinheritance.Main - PigMethod1:Method
继承父类的方法
17:11:47.840 [main] INFO com.kdz.annotationinheritance.Main - PigMethod2:Method

在这里插入图片描述

结论

自定义注解上有@Inherited自定义注解上无@Inherited
子类的类上能否继承到父类的类上的注解?×
子类方法,重写了父类上的方法,这个方法能否继承到注解?××
子类方法,继承了父类上的方法,这个方法能否继承到注解?

使用特定工具方法(如Spring的AnnotatedElementUtils.findMergedAnnotation())来合并注解信息,父类的类级别、方法注解对子类都是可见

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

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

相关文章

如何卸载ollama

文章目录 一 概述二 卸载2.1 Windows平台卸载 ollama2.2 Linux 平台卸载 ollama2.3 Docker 平台卸载 ollama 参考链接 一 概述 本文档主要讲述 ollama 如何卸载,适用范围包括 Windows Linux 以及 Docker 等平台的安装方式。 二 卸载 2.1 Windows平台卸载 ollama …

【干货】SaaS增长|提高销售转化率,用这几个方法就对了!

一、什么是销售转化率 1. 定义 销售转化率是指将潜在客户转化为实际购买者的比率。它衡量了销售过程中的效率和效果,对于评估销售团队的表现和制定销售策略非常重要。 2. 计算公式 销售转化率 (实际购买客户数 / 潜在客户数) 100% 实际购买客户数:…

【python深度学习】——tensor内部存储结构|内存优化与as_strided|内存紧凑化contiguous

【python深度学习】——tensor内部存储结构|内存优化与as_strided|内存紧凑化contiguous 1. tensor的元数据(metadata)和存储区(storage)1.1 元数据(metadata)1.2 存储区(Storage)1.…

excel公式怎么完全复制到另一列?

例如:A1单元格的内容是E1F1;想要复制到B列,内容也是E1F1,而不是F1G1;怎么做呢? 如果公式复制粘贴到其它位置出现偏差,通常有这么两个原因: 一、公式中的相对引用或混合引起 这个情…

操作字符串获取文件后缀名

记录一种操作字符串获取文件类型的操作方式,方便后期的使用。示例: 输入:"D:/code/Test/Test.txt" 输出:".txt" 设计逻辑: 1.通过查找”/“或者”\\“,找到文件名所在位置&#xff…

【并发程序设计】总篇集(八万字)

11_Concurrent_Programing 1.进程概念 在Linux中,进程是操作系统分配资源和调度运行的基本单位。 Linux中的进程有以下用处: 提高CPU利用率:通过进程的并发执行,可以让多个程序同时利用计算机的资源,这样每个用户都…

学习 SSH Key 生成方法

SSH Key 是用于身份验证的一对密钥,包括公钥和私钥。公钥可以放在需要访问的服务器上,私钥则保留在本地。当你使用SSH连接到支持SSH Key认证的服务器时,服务器会用公钥来加密一个随机生成的字符串发送给客户端,客户端用私钥解密并…

(ICLR,2024)HarMA:高效的协同迁移学习与模态对齐遥感技术

文章目录 相关资料摘要引言方法多模态门控适配器目标函数 实验 相关资料 论文:Efficient Remote Sensing with Harmonized Transfer Learning and Modality Alignment 代码:https://github.com/seekerhuang/HarMA 摘要 随着视觉和语言预训练&#xf…

vscode快捷键英文单词对照表

今天想改我的vscode快捷键,unfoldall这条跟我其他的ide都不一样,我得挨个记……但是ctrlshiftp一打开快捷键 点击右侧齿轮进行快捷键录制,但是我这次点左边进去查看了一下unfoldall当前是什么 后来看到了……这些oem_5是什么鬼? {…

03-07Java自动化之JAVA基础之循环

JAVA基础之循环 一、for循环 1.1for循环的含义 for(初始化语句;条件判断;条件控制或–){ ​ //代码语句 } 1、首先执行初始话语句,给变量一个起始的值 2、条件判断进行判断,为true,执行循环体中的代码语句 ​ …

从零开始学习Linux(9)----文件系统

1.前言 1.铺垫 a.文件内容属性 b.访问文件之前,都得先打开,修改文件,都是通过执行代码的方式完成修改,文件必须被加载到内存中 c.谁打开文件?进程在打开文件 d.一个进程可以打开多少个文件呢?可以打开多个…

idea springboot woff/woff2/eot/ttf/svg等小图标不显示的问题 - 第515篇

历史文章(文章累计500) 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 《…

swiftUI使用VideoPlayer和AVPlayer播放视频

使用VideoPlayer包播放视频:https://github.com/wxxsw/VideoPlayer 提供一些可供测试的视频链接,不保证稳定可用哦: https://vfx.mtime.cn/Video/2019/06/15/mp4/190615103827358781.mp4https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp…

基于ssh的实验室设备管理系统java项目实验室管理系统spring项目jsp项目

文章目录 实验室设备管理系统一、项目演示二、项目介绍三、系统部分功能截图四、部分代码展示五、底部获取项目源码(9.9¥带走) 实验室设备管理系统 一、项目演示 实验室设备管理系统 二、项目介绍 基于sshjsp的实验室设备管理系统 系统角色…

6-Django项目--分页模块化封装参数共存

目录 utils/page_data.py 分页模块化封装 在app当中创建一个python package 在当前包里面创建py文件 参数共存 完整代码 utils/page_data.py --包里创建py文件. # -*- coding:utf-8 -*- from django.utils.safestring import mark_safe from copy import deepcopyclass…

网线水晶头为什么要按标准线序打

网线接水晶头为什么要按照线序接? 减少串扰和增强信号质量: 双绞线的设计是为了减少信号间的串扰( Crosstalk),每一对线芯在传输过程中通过相互扭绞抵消外部电磁干扰。按照标准线序接线能够确保每一对线芯之间的信号传…

maridb10.4.30数据库数据迁移

1.新建数据存储文件夹,例如E:\maridb_data 2.修改原数据所在目录的my.ini文件,例如D:\Program Files\MariaDB 10.4\data\my.ini 3.剪切除my.ini文件外的其他所有文件到迁移目的地文件(E:\maridb_data) 结果如下: 原数据文件目录&#xff1a…

MySQL—约束—外键约束(基础)

一、引言 概念:外键用来让两张表的数据之间建立连接,从而保证数据的一致性和完整性。 举个例子: 提示说明:(有两张表) (1)员工表:emp id:主键、姓名、年龄、…

qt+ffmpeg 实现音视频播放(四)之音视频同步

在处理音视频数据时,解码音频的数据往往会比解码视频的数据比较慢,所以我们在播放音视频时,音频和视频的数据会出现渐渐对不上的情况。尤其在播放时间越长的时候,这种对不上的现象越明显。 为了解决这一问题,人们想出…

485通讯网关

在工业自动化与智能化的浪潮中,数据的传输与交互显得尤为重要。作为这一领域的核心设备,485通讯网关凭借其卓越的性能和广泛的应用场景,成为了连接不同设备、不同协议之间数据转换和传输的桥梁。在众多485通讯网关中,HiWoo Box以其…