深入理解java注解,java的4个元注解,注解三要素——定义、使用及读取执行,深入了解注解的底层本质,通过反射自动、动态获取注解所有属性以及属性值

本文详细介绍了Java注解的定义、使用、读取执行,重点讲解了java的4个元注解@Documented、@Inherited、@Retention和@Target的含义和应用。通过实例探讨了如何通过反射动态获取注解的属性及属性值,揭示了注解的本质。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 注解的定义

注解也是一种引用类型,编译后会生成 .class 字节码文件,作用就是为程序进行标识,不同注解能实现不同功能。

2. 注解的使用

3. 注解的读取执行

3.1 得不到注解信息,得到的是null

3.2 在MyAnnotation1注解 加上 @Retention(RetentionPolicy.RUNTIME) 以及 MyAnnotation3注解 加上 @Retention(RetentionPolicy.CLASS)后,得到了MyAnnotation1注解信息,但没得到MyAnnotation3注解信息,如下图。

 

4. java中的4个元注解:@Documented、@Inherited、@Retention和@Target

4.1 @Documented注解使用后会被javadoc工具处理,内部没有属性,@Documented注解源代码如下图。

4.2 @Inherited注解:包含@Inherited的注解会被子类继承;@Inherited注解只能在类使用,不能用于方法、属性等;查询某个类是否使用了包含@Inherited的注解时,不仅会查询当前类,还会在父类中查询,直至到达Object类。@Inherited注解源代码及使用如下图。

4.3 @Target注解:指定注解被用于什么位置,是用在类上还是方法上或是属性等等,由ElementType数组指定,可指定的位置主要有10种,@Target注解源代码及ElementType取值范围及@Target注解使用如下图所示。

4.4 @Retention注解:表示注解保存到什么时候。@Retention注解源代码及RetentionPolicy取值范围如下图所示,@Retention注解的使用在3.2中已经分析过。

5. 深入了解注解的本质及动态获取注解属性值

5.1 我们以MyAnnotation2和MyAnnotation3注解为例,代码如下。

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
    int age();
    String name();
    int[] hobby();
}

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
    String value();
}

5.2 然后使用注解的测试类AnnotationTest代码如下。

5.3 读取注解并执行,代码如下。

5.4 到这里,我们是不是算完成注解的定义、使用及读取了呢?其实这边还有两个问题:1.为什么注解中的属性获取和执行方法形式一致?2.我们可不可以动态、自动地获取注解的所有属性及属性值呢?

5.5 我们先加载注解MyAnnotation2,并查看一下注解的信息,如下图。

同时查看一下字节码的反编译代码,虽然注解的形式和接口几乎一致,但是有一个操作我们很费解,就是可以给注解里的属性赋值,我们刚说完注解的属性实际是方法,那么方法怎么能赋值呢?所以这里有个奇怪的点,所以我们还是要特别对待注解和接口

5.6 既然注解中的属性实际上是方法,那么想通过反射获取属性值,是不是也是通过方法反射,而不是属性反射呢?结果如下图。

5.7  通过5.5和5.6,我们解决了两个问题:为什么注解中的属性和方法一样的形式;怎么能够通过反射自动、动态地获取注解所有属性及属性值。

附录:代码和最终运行结果

import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

@MyAnnotation3("class_annotation")
public class AnnotationTest{
    @MyAnnotation3("mem_annotation")
    private String mem;

    public static void main(String[] args) throws Exception {
        // 通过反射得到AnnotationTest类
        Class<?> annotationTest = Class.forName("AnnotationTest");

        // 获取AnnotationTest类使用的MyAnnotation3注解
        MyAnnotation3 annotation = annotationTest.getAnnotation(MyAnnotation3.class);
        System.out.println("获取类AnnotationTest使用的MyAnnotation3注解信息:" + annotation);

        // 通过反射,动态获取AnnotationTest类的所有属性
        // 这里要注意getDeclaredFields方法是得到当前类所有声明的方法,不管访问权限,但不包含父类的方法
        // getFields方法则是得到访问权限是public的方法,包含父类的公共方法。
        Field[] declaredFields = annotationTest.getDeclaredFields();
        for(Field f: declaredFields){
            // 获取属性使用的MyAnnotation3注解信息
            MyAnnotation3 annotation1 = f.getAnnotation(MyAnnotation3.class);
            if(annotation1 != null){
                System.out.println("获取属性mem使用的MyAnnotation3注解的value属性值:" +  annotation1.value());
            }
        }

        // 与上面类似
        Method[] declaredMethods = annotationTest.getDeclaredMethods();
        Class<?> myAnnotation2 = Class.forName("MyAnnotation2");
        for(Method m: declaredMethods){
            MyAnnotation2 annotation1 = m.getAnnotation(MyAnnotation2.class);
            if(annotation1 != null){
                // 通过反射自动、动态地获取注解的属性及属性值
                System.out.print("通过反射获取MyAnnotation2注解的属性及属性值, ");
                Method[] declaredMethods2 = myAnnotation2.getDeclaredMethods();
                for(Method mm: declaredMethods2){
                    if(mm.getName().equals("hobby")){
                        System.out.print(mm.getName() + ":" + Arrays.toString((int[])mm.invoke(annotation1)) + "  ");
                    }else{
                        System.out.print(mm.getName() + ":" + mm.invoke(annotation1) + "  ");
                    }
                }
                System.out.println();
            }

            MyAnnotation3 annotation2 = m.getAnnotation(MyAnnotation3.class);
            if(annotation2 != null){
                System.out.println("获取方法" + m.getName() + "使用的MyAnnotation3注解信息: " + annotation2.value());
            }
        }
    }

    @MyAnnotation3("test1")
    static void test1(){
    }

    @MyAnnotation2(name = "lhj", age = 15, hobby = {1,3})
    static void test2(){
    }
}

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
    int age();
    String name();
    int[] hobby();
}

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
    String value();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值