注解反射注解

📅 2026/7/5 21:40:32
注解反射注解
注解反射注解1. 注解的定义1.1 注解属性的类型1.2 定义格式1.3 注解的使用2. 作用目标限定以及保存策略限定2.1 作用目标限定2.2 保存策略限定3. 注解反射3.1 作用目标上返回3.2 获取方法4. Class 获取注解6个核心方法完整区分4.1 不带 Declared会递归获取父类、接口上的注解4.2 带 Declared仅读取**本类直接标注**的注解忽略父类、接口4.3 补充三个特殊方法4.4 开发场景速记1. 注解的定义public interface Annotation 是所有的注解的父接口1.1 注解属性的类型8种基本类型 byte short char int long float double booleanStringEnumClass注解类型以上类型的一维数组类型1.2 定义格式publicinterfaceMyAnno{intage()default22;Stringname();MyEnummyEnum();Classclazz();YourAnnoanno();String[]value();}注意自定义类类型是不允许的定义注解时可以给注解属性指定默认值使用时可以不给带有默认值的属性赋值。1.3 注解的使用MyAnno(nameXiaoMing,myEnumMyEnum.RED,clazzObject.class,annoYourAnno,valueHello)publicclassAnnoTest{}当使用注解时如果只给名为value的属性赋值时可以省略“value”例如 MyAnno1(value“hello”)可以书写成 MyAnno1(“hello”)当给数组类型的属性赋值时若数组元素的个数为1时可以省略大括号所以有简写publicinterfaceMyAnno{String[]value();}MyAnno(Hello)publicclassAnnoTest{}2. 作用目标限定以及保存策略限定2.1 作用目标限定这代码中有这些位置可以使用注解接口、类、枚举注解字段、枚举常量方法构造器参数局部变量包那我们如何限定只有某几个位置可以使用该注解呢答案给注解添加Target注解来限定作用目标注意如果定义注解不写Target(xxx)默认允许标注所有合法位置全部 ElementType 都生效等价于Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, TYPE_PARAMETER, TYPE_USE, MODULE, RECORD_COMPONENT})Target源码DocumentedRetention(RetentionPolicy.RUNTIME)Target(ElementType.ANNOTATION_TYPE)publicinterfaceTarget{/** * Returns an array of the kinds of elements an annotation type * can be applied to. * return an array of the kinds of elements an annotation type * can be applied to */ElementType[]value();// 枚举数组}ElementTypepublicenumElementType{/** Class, interface (including annotation type), or enum declaration */// 类接口包含注解或 枚举TYPE,/** Field declaration (includes enum constants) */// 字段包括枚举常量FIELD,/** Method declaration */// 方法声明METHOD,/** Formal parameter declaration */// 参数声明PARAMETER,/** Constructor declaration */// 构造方法声明CONSTRUCTOR,/** Local variable declaration */// 局部变量声明LOCAL_VARIABLE,/** Annotation type declaration */// 注解类型ANNOTATION_TYPE,/** Package declaration */// 包PACKAGE,/** * Type parameter declaration * * since 1.8 */// 泛型参数声明TYPE_PARAMETER,/** * Use of a type * * since 1.8 */// 泛型类型TYPE_USE}其中有两个是jdk1.8新加的属性把自定义的注解限定在类或方法上Target(value{ElementType.TYPE,ElementType.METHOD})publicinterfaceMyAnno{intage()default22;Stringname();MyEnummyEnum();Classclazz();YourAnnoanno();String[]value();}2.2 保存策略限定源代码文件SOURCE注解只在源代码中存在当编译时就被忽略了字节码文件CLASS默认注解在源代码中存在然后编译时会把注解信息放到了class文件但JVM在加载类时会忽略注解JVM中RUNTIME注解在源代码、字节码文件中存在并且在JVM加载类时会把注解加载到JVM内存中它是唯一可反射注解使用Retention注解保留策略DocumentedRetention(RetentionPolicy.RUNTIME)Target(ElementType.ANNOTATION_TYPE)publicinterfaceRetention{/** * Returns the retention policy. * return the retention policy */RetentionPolicyvalue();}RetentionPolicypublicenumRetentionPolicy{/** * Annotations are to be discarded by the compiler. */SOURCE,/** * Annotations are to be recorded in the class file by the compiler * but need not be retained by the VM at run time. This is the default * behavior. */CLASS,/** * Annotations are to be recorded in the class file by the compiler and * retained by the VM at run time, so they may be read reflectively. * * see java.lang.reflect.AnnotatedElement */RUNTIME}给自定义注解加保留策略Retention(RetentionPolicy.RUNTIME)Target(value{ElementType.TYPE,ElementType.METHOD})publicinterfaceMyAnno{intage()default22;Stringname();MyEnummyEnum();Classclazz();YourAnnoanno();String[]value();}这样就可以使用反射获取注解的值了这也是很多框架注解常用的定义方式。3. 注解反射要想反射注解的保留策略必须是RUNTIME3.1 作用目标上返回类上的注解需要使用Class来获取方法上的注解需要Method来获取构造器上的注解需要Construcator来获取成员上的需要使用Field来获取…3.2 获取方法Annotation getAnnotation(Class)返回目标上指定类型的注解Annotation[] getAnnotations()返回目标上所有注解publicclassAnnoTestTest{TestpublicvoidtestAnnoReflect(){ClassAnnoTestclazzAnnoTest.class;MyAnnomyAnnoclazz.getAnnotation(MyAnno.class);System.out.println(age: myAnno.age());System.out.println(name: myAnno.name());System.out.println(myEnum: myAnno.myEnum());System.out.println(clazz: myAnno.clazz());System.out.println(myAnno: myAnno.anno());System.out.println(value: Arrays.toString(myAnno.value()));System.out.println(--------------------------------------);Annotation[]annotationsclazz.getAnnotations();for(Annotationannotation:annotations){if(annotationinstanceofMyAnno){System.out.println(是自定义注解MyAnno);}}}}测试结果age: 22 name: XiaoMing myEnum: RED clazz: class java.lang.Object myAnno: com.yp.anno.YourAnno() value: [Hello] -------------------------------------- 是自定义注解MyAnno4. Class 获取注解6个核心方法完整区分4.1 不带 Declared会递归获取父类、接口上的注解getAnnotation(ClassA annoClass)作用查询当前类 所有父类/接口找到第一个匹配的注解返回匹配到的注解对象找不到返回null适用需要读取父类标注注解Spring常用如Component子类也能拿到getAnnotations()作用获取当前类父类接口上全部注解去重返回Annotation[]注解数组getAnnotationsByType(ClassA annoClass)作用获取当前类父类接口上所有同类型注解支持Repeatable重复注解返回该注解类型的数组4.2 带 Declared仅读取本类直接标注的注解忽略父类、接口getDeclaredAnnotation(ClassA annoClass)作用只看当前类自身写的注解不往上找父类返回本类匹配注解无则nullgetDeclaredAnnotations()作用仅返回当前类直接标注的全部注解父类注解完全忽略返回Annotation[]getDeclaredAnnotationsByType(ClassA annoClass)作用仅读取本类上该类型的所有重复注解不递归父类返回对应注解数组方法是否读取父类/接口注解用途getAnnotation✅ 会向上递归获取类上某一个注解包含继承来的getAnnotations✅ 会向上递归获取所有注解包含父类getAnnotationsByType✅ 会向上递归获取同类型全部重复注解含父类getDeclaredAnnotation❌ 仅当前类只拿本类直接写的注解getDeclaredAnnotations❌ 仅当前类只拿本类全部注解getDeclaredAnnotationsByType❌ 仅当前类只拿本类的同类型重复注解4.3 补充三个特殊方法getAnnotatedSuperclass()获取父类的类型注解TYPE_USE/TYPE_PARAMETER普通Target(TYPE)类注解不用这个。getAnnotatedInterfaces()获取实现接口上的类型注解。Class? extends Annotation annotationType()java.lang.annotation.Annotation的方法可获取注解上的元注解可递归获取注解上的注解这个方法很重要4.4 开发场景速记自定义注解 Inherited可继承注解用getAnnotation/getAnnotations能拿到父类注解只想看当前类自己加的注解不关心父类统一用getDeclaredXXX使用了Repeatable重复注解必须用XXXByType普通getAnnotation只能拿第一个。只有注解标注Retention(RetentionPolicy.RUNTIME)这些反射方法才能读到默认CLASS保留策略运行时全部返回null。