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

在解决这个问题之前需要先了解一下@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())来合并注解信息,父类的类级别、方法注解对子类都是可见

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小孔靠得住

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值