欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

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

发布时间:2025/3/19 编程问答 29 豆豆

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(); }

总结

以上是生活随笔为你收集整理的深入理解java注解,java的4个元注解,注解三要素——定义、使用及读取执行,深入了解注解的底层本质,通过反射自动、动态获取注解所有属性以及属性值的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。