Java关于Annotation详解
Annotation的架构图:

可以看出:
(01) 1个Annotation 和 1个RetentionPolicy关联。
可以理解为:每1个Annotation对象,都会有唯一的RetentionPolicy属性。
(02) 1个Annotation 和 1~n个ElementType关联。
可以理解为:对于每1个Annotation对象,可以有若干个ElementType属性。
(03) Annotation 有许多实现类,包括:Deprecated, Documented, Inherited, Override等等。
Annotation 的每一个实现类,都“和1个RetentionPolicy关联”并且“和1~n个ElementType关联”。
Annotation组成成分
Annotation.java
package java.lang.annotation; public interface Annotation { boolean equals(Object obj); int hashCode(); String toString(); Class<? extends Annotation> annotationType(); }
ElementType.java
package java.lang.annotation; public enum ElementType { TYPE, /* 类、接口(包括注释类型)或枚举声明 */ FIELD, /* 字段声明(包括枚举常量) */ METHOD, /* 方法声明 */ PARAMETER, /* 参数声明 */ CONSTRUCTOR, /* 构造方法声明 */ LOCAL_VARIABLE, /* 局部变量声明 */ ANNOTATION_TYPE, /* 注释类型声明 */ PACKAGE /* 包声明 */ }
RetentionPolicy.java
package java.lang.annotation; public enum RetentionPolicy { SOURCE, /* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了 */ CLASS, /* 编译器将Annotation存储于类对应的.class文件中。默认行为 */ RUNTIME /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */ }
说明:
(01) Annotation 是个接口。
“每1个Annotation” 都与 “1个RetentionPolicy”关联,并且与 “1~n个ElementType”关联。可以通俗的理解为:每1个Annotation对象,都会有唯一的RetentionPolicy属性;至于ElementType属性,则有1~n个。
(02) ElementType 是Enum枚举类型,用来指定Annotation的类型。
“每1个Annotation” 都与 “1~n个ElementType”关联。当Annotation与某个ElementType关联时,就意味着:Annotation有了某种用途。
例如,若一个Annotation对象是METHOD类型,则该Annotation只能用来修饰方法。
(03) RetentionPolicy 是Enum枚举类型,用来指定Annotation的策略。通俗点说,就是不同RetentionPolicy类型的Annotation的作用域不同。
“每1个Annotation” 都与 “1个RetentionPolicy”关联。
a) 若Annotation的类型为 SOURCE,则意味着:Annotation仅存在于编译器处理期间,编译器处理完之后,该Annotation就没用了。
例如,“ @Override ”标志就是一个Annotation。当它修饰一个方法的时候,就意味着该方法覆盖父类的方法;并且在编译期间会进行语法检查!编译器处理完 后,“@Override”就没有任何作用了。
b) 若Annotation的类型为 CLASS,则意味着:编译器将Annotation存储于类对应的.class文件中,是Annotation的默认行为。
c) 若Annotation的类型为 RUNTIME,则意味着:编译器将Annotation存储于class文件中,并且可由JVM读入。
这时,只需要记住“每1个Annotation” 都与 “1个RetentionPolicy”关联,并且与 “1~n个ElementType”关联。
示例
@Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation1 { }
说明:
定义一个Annotation,名字是MyAnnotation1。定义了MyAnnotation1之后,可以在代码中通过“@MyAnnotation1”来使用它。
其它的,@Documented, @Target, @Retention, @interface都是来修饰MyAnnotation1的。下面分别说说它们的含义:
(01) @interface
使用@interface定义注解时,意味着它实现java.lang.annotation.Annotation接口,即该注解就是一个Annotation。
定义Annotation时,@interface是必须的
注意:和我们通常的implemented实现接口的方法不同。Annotation接口的实现细节都由编译器完成。通过@interface定义注解后,该注解不能继承其他的注解或接口。
(02) @Documented
类和方法的Annotation在缺省情况下是不出现在javadoc中的。如果使用@Documented修饰该Annotation,则表示它可以出现在javadoc中。
定义Annotation时,@Documented可有可无;若没有定义,则Annotation不会出现在javadoc中。
(03) @Target(ElementType.TYPE)
ElementType 是Annotation的类型属性。而@Target的作用,就是来指定Annotation的类型属性。
@Target(ElementType.TYPE) 的意思就是指定该Annotation的类型是ElementType.TYPE。这就意味着,MyAnnotation1是来修饰“类、接口(包括注释类型)或枚举声明”的注解。
定义Annotation时,@Target可有可无。若有@Target,则该Annotation只能用于它所指定的地方;若没有@Target,则该Annotation可以用于任何地方。
(04) @Retention(RetentionPolicy.RUNTIME)
RetentionPolicy 是Annotation的策略属性,而@Retention的作用,就是指定Annotation的策略属性。
@Retention(RetentionPolicy.RUNTIME) 的意思就是指定该Annotation的策略是RetentionPolicy.RUNTIME。这就意味着,编译器会将该Annotation信息保留在.class文件中,并且能被虚拟机读取。
定义Annotation时,@Retention可有可无。若没有@Retention,则默认是RetentionPolicy.CLASS。
Annotation
@interface用来声明Annotation,@Documented用来表示该Annotation是否会出现在javadoc中, @Target用来指定Annotation的类型,@Retention用来指定Annotation的策略。

java 常用的Annotation:
@Deprecated -- @Deprecated 所标注内容,不再被建议使用。 @Override -- @Override 只能标注方法,表示该方法覆盖父类中的方法。 @Documented -- @Documented 所标注内容,可以出现在javadoc中。 @Inherited -- @Inherited只能被用来标注“Annotation类型”,它所标注的Annotation具有继承性。 @Retention -- @Retention只能被用来标注“Annotation类型”,而且它被用来指定Annotation的RetentionPolicy属性。 @Target -- @Target只能被用来标注“Annotation类型”,而且它被用来指定Annotation的ElementType属性。 @SuppressWarnings -- @SuppressWarnings 所标注内容产生的警告,编译器会对这些警告保持静默。
@Deprecated 的定义如下:
@Documented @Retention(RetentionPolicy.RUNTIME) public @interface Deprecated { }
说明:
(01) @interface -- 它的用来修饰Deprecated,意味着Deprecated实现了java.lang.annotation.Annotation接口;即Deprecated就是一个注解。
(02) @Documented -- 作用是说明该注解能出现在javadoc中。
(03) @Retention(RetentionPolicy.RUNTIME) -- 它的作用是指定Deprecated的策略是RetentionPolicy.RUNTIME。这就意味着,编译器会将Deprecated的信息保留在.class文件中,并且能被虚拟机读取。
(04) @Deprecated 所标注内容,不再被建议使用。
@Inherited 的定义如下
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Inherited { }
说明:
(01) @interface -- 用来修饰Inherited,意味着Inherited实现了java.lang.annotation.Annotation接口;即Inherited就是一个注解。
(02) @Documented -- 作用是说明该注解能出现在javadoc中。
(03) @Retention(RetentionPolicy.RUNTIME) -- 作用是指定Inherited的策略是RetentionPolicy.RUNTIME。这就意味着,编译器会将Inherited的信息保留在.class文件中,并且能被虚拟机读取。
(04) @Target(ElementType.ANNOTATION_TYPE) -- 作用是指定Inherited的类型是ANNOTATION_TYPE。这就意味着,@Inherited只能被用来标注“Annotation类型”。
(05) @Inherited 的含义是,它所标注的Annotation将具有继承性。
定义了某个Annotaion,名称是MyAnnotation,并且MyAnnotation被标注为@Inherited。某个类Base使用了MyAnnotation,则Base具有了“具有了注解MyAnnotation”;Sub继承了Base,由于MyAnnotation是@Inherited的(具有继承性),所以,Sub也“具有了注解MyAnnotation”。
/** * @Inherited 演示示例 * */ package com.skywang.annotation; import java.lang.annotation.Target; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Inherited; /** * 自定义的Annotation。 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited @interface Inheritable { } @Inheritable class InheritableFather { public InheritableFather() { // InheritableBase是否具有 Inheritable Annotation System.out.println("InheritableFather:"+InheritableFather.class.isAnnotationPresent(Inheritable.class)); } } /** * InheritableSon 类只是继承于 InheritableFather, */ public class InheritableSon extends InheritableFather { public InheritableSon() { super(); // 调用父类的构造函数 // InheritableSon类是否具有 Inheritable Annotation System.out.println("InheritableSon:"+InheritableSon.class.isAnnotationPresent(Inheritable.class)); } public static void main(String[] args) { InheritableSon is = new InheritableSon(); } } 结果: true true
对InheritableSon.java进行修改:注释掉“Inheritable的@Inherited注解”:返回 true false
@SuppressWarnings 的定义如下:
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { String[] value(); }
说明:
(01) @interface -- 它的用来修饰SuppressWarnings,意味着SuppressWarnings实现java.lang.annotation.Annotation接口;即SuppressWarnings就是一个注解。
(02) @Retention(RetentionPolicy.SOURCE) -- 作用是指定SuppressWarnings的策略是RetentionPolicy.SOURCE。意味着,SuppressWarnings信息仅存在于编译器处理期间,编译器处理完之后SuppressWarnings就没有作用了。
(03) @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) -- 它的作用是指定SuppressWarnings的类型同时包括TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE。
TYPE意味着,它能标注“类、接口(包括注释类型)或枚举声明”。
FIELD意味着,它能标注“字段声明”。
METHOD意味着,它能标注“方法”。
PARAMETER意味着,它能标注“参数”。
CONSTRUCTOR意味着,它能标注“构造方法”。
LOCAL_VARIABLE意味着,它能标注“局部变量”。
(04) String[] value(); 意味着,SuppressWarnings能指定参数
(05) SuppressWarnings 的作用是,让编译器对“它所标注的内容”的某些警告保持静默。例如,"@SuppressWarnings(value={"deprecation", "unchecked"})" 表示对“它所标注的内容”中的 “SuppressWarnings不再建议使用警告”和“未检查的转换时的警告”保持沉默。
作用:
让编译器进行编译检查的作用

若某个方法被 @Override的 标注,则意味着该方法会覆盖父类中的同名方法。如果有方法被@Override标示,但父类中却没有“被@Override标注”的同名方法,则编译器会报错
反射中使用Annotation
import java.lang.annotation.Annotation; import java.lang.annotation.Target; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Inherited; import java.lang.reflect.Method; /** * Annotation在反射函数中的使用示例 */ @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation { String[] value() default "unknown"; } /** * Person类。它会使用MyAnnotation注解。 */ class Person { /** * empty()方法同时被 "@Deprecated" 和 “@MyAnnotation(value={"a","b"})”所标注 * (01) @Deprecated, 意味着empty()方法,不再被建议使用 * (02) @MyAnnotation, 意味着empty() 方法对应的MyAnnotation的value值是默认值"unknown" */ @MyAnnotation @Deprecated public void empty(){ System.out.println("\nempty"); } /** * sombody() 被 @MyAnnotation(value={"girl","boy"}) 所标注, * @MyAnnotation(value={"girl","boy"}), 意味着MyAnnotation的value值是{"girl","boy"} */ @MyAnnotation(value={"girl","boy"}) public void somebody(String name, int age){ System.out.println("\nsomebody: "+name+", "+age); } } public class AnnotationTest { public static void main(String[] args) throws Exception { // 新建Person Person person = new Person(); // 获取Person的Class实例 Class<Person> c = Person.class; // 获取 somebody() 方法的Method实例 Method mSomebody = c.getMethod("somebody", new Class[]{String.class, int.class}); // 执行该方法 mSomebody.invoke(person, new Object[]{"lily", 18}); iteratorAnnotations(mSomebody); // 获取 somebody() 方法的Method实例 Method mEmpty = c.getMethod("empty", new Class[]{}); // 执行该方法 mEmpty.invoke(person, new Object[]{}); iteratorAnnotations(mEmpty); } public static void iteratorAnnotations(Method method) { // 判断 somebody() 方法是否包含MyAnnotation注解 if(method.isAnnotationPresent(MyAnnotation.class)){ // 获取该方法的MyAnnotation注解实例 MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class); // 获取 myAnnotation的值,并打印出来 String[] values = myAnnotation.value(); for (String str:values) System.out.printf(str+", "); System.out.println(); } // 获取方法上的所有注解,并打印出来 Annotation[] annotations = method.getAnnotations(); for(Annotation annotation : annotations){ System.out.println(annotation); } } }
运行结果:
somebody: lily, 18
girl, boy,
@com.skywang.annotation.MyAnnotation(value=[girl, boy])
empty
unknown,
@com.skywang.annotation.MyAnnotation(value=[unknown])
@java.lang.Deprecated()
快捷方式就是注解中定义了名为value的元素,并且在使用该注解时,如果该元素是唯一需要赋值的一个元素,那么此时无需使用key=value的语法,而只需在括号内给出value元素所需的值即可。这可以应用于任何合法类型的元素,记住,这限制了元素名必须为value,简单案例如下
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; //定义注解 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface IntegerVaule{ int value() default 0; String name() default ""; } //使用注解 public class QuicklyWay { //当只想给value赋值时,可以使用以下快捷方式 @IntegerVaule(20) public int age; //当name也需要赋值时必须采用key=value的方式赋值 @IntegerVaule(value = 10000,name = "MONEY") public int money; }
运行时注解处理器
利用运行时注解来组装数据库SQL的构建语句的过程
/** * 表注解 */ @Target(ElementType.TYPE)//只能应用于类上 @Retention(RetentionPolicy.RUNTIME)//保存到运行时 public @interface DBTable { String name() default ""; } /** * 注解Integer类型的字段 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface SQLInteger { //该字段对应数据库表列名 String name() default ""; //嵌套注解 Constraints constraint() default @Constraints; } /** * 注解String类型的字段 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface SQLString { //对应数据库表的列名 String name() default ""; //列类型分配的长度,如varchar(30)的30 int value() default 0; Constraints constraint() default @Constraints; } /** * 约束注解 */ @Target(ElementType.FIELD)//只能应用在字段上 @Retention(RetentionPolicy.RUNTIME) public @interface Constraints { //判断是否作为主键约束 boolean primaryKey() default false; //判断是否允许为null boolean allowNull() default false; //判断是否唯一 boolean unique() default false; } /** * 数据库表Member对应实例类bean */ @DBTable(name = "MEMBER") public class Member { //主键ID @SQLString(name = "ID",value = 50, constraint = @Constraints(primaryKey = true)) private String id; @SQLString(name = "NAME" , value = 30) private String name; @SQLInteger(name = "AGE") private int age; @SQLString(name = "DESCRIPTION" ,value = 150 , constraint = @Constraints(allowNull = true)) private String description;//个人描述 //省略set get..... }
import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; /** * 运行时注解处理器,构造表创建语句 */ public class TableCreator { public static String createTableSql(String className) throws ClassNotFoundException { Class<?> cl = Class.forName(className); DBTable dbTable = cl.getAnnotation(DBTable.class); //如果没有表注解,直接返回 if(dbTable == null) { System.out.println("No DBTable annotations in class "+className); return null; } String tableName = dbTable.name(); // If the name is empty, use the Class name: if(tableName.length() < 1) tableName = cl.getName().toUpperCase(); List<String> columnDefs = new ArrayList<String>(); //通过Class类API获取到所有成员字段 for(Field field : cl.getDeclaredFields()) { String columnName = null; //获取字段上的注解 Annotation[] anns = field.getDeclaredAnnotations(); if(anns.length < 1) continue; // Not a db table column //判断注解类型 if(anns[0] instanceof SQLInteger) { SQLInteger sInt = (SQLInteger) anns[0]; //获取字段对应列名称,如果没有就是使用字段名称替代 if(sInt.name().length() < 1) columnName = field.getName().toUpperCase(); else columnName = sInt.name(); //构建语句 columnDefs.add(columnName + " INT" + getConstraints(sInt.constraint())); } //判断String类型 if(anns[0] instanceof SQLString) { SQLString sString = (SQLString) anns[0]; // Use field name if name not specified. if(sString.name().length() < 1) columnName = field.getName().toUpperCase(); else columnName = sString.name(); columnDefs.add(columnName + " VARCHAR(" + sString.value() + ")" + getConstraints(sString.constraint())); } } //数据库表构建语句 StringBuilder createCommand = new StringBuilder( "CREATE TABLE " + tableName + "("); for(String columnDef : columnDefs) createCommand.append("\n " + columnDef + ","); // Remove trailing comma String tableCreate = createCommand.substring( 0, createCommand.length() - 1) + ");"; return tableCreate; } /** * 判断该字段是否有其他约束 * @param con * @return */ private static String getConstraints(Constraints con) { String constraints = ""; if(!con.allowNull()) constraints += " NOT NULL"; if(con.primaryKey()) constraints += " PRIMARY KEY"; if(con.unique()) constraints += " UNIQUE"; return constraints; } public static void main(String[] args) throws Exception { String[] arg={"com.zejian.annotationdemo.Member"}; for(String className : arg) { System.out.println("Table Creation SQL for " + className + " is :\n" + createTableSql(className)); } /** * 输出结果: Table Creation SQL for com.zejian.annotationdemo.Member is : CREATE TABLE MEMBER( ID VARCHAR(50) NOT NULL PRIMARY KEY, NAME VARCHAR(30) NOT NULL, AGE INT NOT NULL, DESCRIPTION VARCHAR(150) ); */ } }
元注解@Repeatable
元注解@Repeatable是JDK1.8新加入的,它表示在同一个位置重复相同的注解。在没有该注解前,一般是无法在同一个类型上使用相同的注解的
//Java8前无法这样使用 @FilterPath("/web/update") @FilterPath("/web/add") public class A {}
Java8前如果是想实现类似的功能,我们需要在定义@FilterPath注解时定义一个数组元素接收多个值如下
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface FilterPath { String [] value(); } //使用 @FilterPath({"/update","/add"}) public class A { }
Java8新增了@Repeatable注解后就可以采用如下的方式定义并使用
//使用Java8新增@Repeatable原注解 @Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Repeatable(FilterPaths.class)//参数指明接收的注解class public @interface FilterPath { String value(); } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface FilterPaths { FilterPath[] value(); } //使用案例 @FilterPath("/web/update") @FilterPath("/web/add") @FilterPath("/web/delete") class AA{ }
通过使用@Repeatable后,将使用@FilterPaths注解作为接收同一个类型上重复注解的容器,而每个@FilterPath则负责保存指定的路径串。为了处理上述的新增注解,Java8还在AnnotatedElement接口新增了getDeclaredAnnotationsByType() 和 getAnnotationsByType()两个方法并在接口给出了默认实现,在指定@Repeatable的注解时,可以通过这两个方法获取到注解相关信息。但请注意,旧版API中的getDeclaredAnnotation()和 getAnnotation()是不对@Repeatable注解的处理的(除非该注解没有在同一个声明上重复出现)。注意getDeclaredAnnotationsByType方法获取到的注解不包括父类,其实当 getAnnotationsByType()方法调用时,其内部先执行了getDeclaredAnnotationsByType方法,只有当前类不存在指定注解时,getAnnotationsByType()才会继续从其父类寻找,但请注意如果@FilterPath和@FilterPaths没有使用了@Inherited的话,仍然无法获取。下面通过代码来演示:
//使用Java8新增@Repeatable原注解 @Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Repeatable(FilterPaths.class) public @interface FilterPath { String value(); } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface FilterPaths { FilterPath[] value(); } @FilterPath("/web/list") class CC { } //使用案例 @FilterPath("/web/update") @FilterPath("/web/add") @FilterPath("/web/delete") class AA extends CC{ public static void main(String[] args) { Class<?> clazz = AA.class; //通过getAnnotationsByType方法获取所有重复注解 FilterPath[] annotationsByType = clazz.getAnnotationsByType(FilterPath.class); FilterPath[] annotationsByType2 = clazz.getDeclaredAnnotationsByType(FilterPath.class); if (annotationsByType != null) { for (FilterPath filter : annotationsByType) { System.out.println("1:"+filter.value()); } } System.out.println("-----------------"); if (annotationsByType2 != null) { for (FilterPath filter : annotationsByType2) { System.out.println("2:"+filter.value()); } } System.out.println("使用getAnnotation的结果:"+clazz.getAnnotation(FilterPath.class)); /** * 执行结果(当前类拥有该注解FilterPath,则不会从CC父类寻找) 1:/web/update 1:/web/add 1:/web/delete ----------------- 2:/web/update 2:/web/add 2:/web/delete 使用getAnnotation的结果:null */ } }
执行结果来看如果当前类拥有该注解@FilterPath,则getAnnotationsByType方法不会从CC父类寻找,下面看看另外一种情况,即AA类上没有@FilterPath注解
//使用Java8新增@Repeatable原注解 @Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited //添加可继承元注解 @Repeatable(FilterPaths.class) public @interface FilterPath { String value(); } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited //添加可继承元注解 @interface FilterPaths { FilterPath[] value(); } @FilterPath("/web/list") @FilterPath("/web/getList") class CC { } //AA上不使用@FilterPath注解,getAnnotationsByType将会从父类查询 class AA extends CC{ public static void main(String[] args) { Class<?> clazz = AA.class; //通过getAnnotationsByType方法获取所有重复注解 FilterPath[] annotationsByType = clazz.getAnnotationsByType(FilterPath.class); FilterPath[] annotationsByType2 = clazz.getDeclaredAnnotationsByType(FilterPath.class); if (annotationsByType != null) { for (FilterPath filter : annotationsByType) { System.out.println("1:"+filter.value()); } } System.out.println("-----------------"); if (annotationsByType2 != null) { for (FilterPath filter : annotationsByType2) { System.out.println("2:"+filter.value()); } } System.out.println("使用getAnnotation的结果:"+clazz.getAnnotation(FilterPath.class)); /** * 执行结果(当前类没有@FilterPath,getAnnotationsByType方法从CC父类寻找) 1:/web/list 1:/web/getList ----------------- 使用getAnnotation的结果:null */ } }
注意定义@FilterPath和@FilterPath时必须指明@Inherited,getAnnotationsByType方法否则依旧无法从父类获取@FilterPath注解,这是为什么呢,不妨看看getAnnotationsByType方法的实现源码:
//接口默认实现方法 default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) { //先调用getDeclaredAnnotationsByType方法 T[] result = getDeclaredAnnotationsByType(annotationClass); //判断当前类获取到的注解数组是否为0 if (result.length == 0 && this instanceof Class && //判断定义注解上是否使用了@Inherited元注解 AnnotationType.getInstance(annotationClass).isInherited()) { // Inheritable //从父类获取 Class<?> superClass = ((Class<?>) this).getSuperclass(); if (superClass != null) { result = superClass.getAnnotationsByType(annotationClass); } } return result; }
参考:
http://www.cnblogs.com/skywang12345/p/3344137.html#top
https://blog.csdn.net/javazejian/article/details/71860633(推荐)
浙公网安备 33010602011771号