深入分析Java反射(一)-核心类库和方法 (3)

运行后输出:

-----getAnnotations----- @org.throwable.inherited.Main$SupperAnnotation(value=SupperAnnotation) @org.throwable.inherited.Main$SubAnnotation(value=SubAnnotation) -----getDeclaredAnnotation-->SupperAnnotation----- null -----getAnnotation-->SupperAnnotation----- @org.throwable.inherited.Main$SupperAnnotation(value=SupperAnnotation) -----getDeclaredAnnotation-->SubAnnotation----- @org.throwable.inherited.Main$SubAnnotation(value=SubAnnotation) -----getDeclaredAnnotationsByType-->SubAnnotation----- @org.throwable.inherited.Main$SubAnnotation(value=SubAnnotation) -----getDeclaredAnnotationsByType-->SupperAnnotation----- -----getAnnotationsByType-->SupperAnnotation----- @org.throwable.inherited.Main$SupperAnnotation(value=SupperAnnotation)

可以尝试注释掉@Inherited再运行一次,对比一下结果。如果注释掉@Inherited,从Sub这个类永远无法获取到它的父类Supper中的@SupperAnnotation。Class、Constructor、Method、Field、Parameter都实现了AnnotatedElement接口,所以它们都具备操作注解的功能。

Member接口

Member接口注解提供成员属性的一些描述,主要提供的方法如下:

方法 功能
Class<?> getDeclaringClass()   获取声明的Class对象,也就是获取当前Member实例的来源Class对象  
String getName()   获取实例的名称,对于Constructor返回全类名,对于Method返回方法名,对于Field返回属性名  
int getModifiers()   获取实例的修饰符  
boolean isSynthetic()   是否合成的  

这些方法里面除了isSynthetic()都比较好理解。synthetic总的来说,是由编译器引入的字段、方法、类或其他结构,主要用于JVM内部使用,为了遵循某些规范而作的一些小技巧从而绕过这些规范,有点作弊的感觉,只不过是由编译器光明正大为之,一般开发者是没有权限的(但事实上有时候还是能被利用到的)。下面这个例子参考自synthetic Java合成类型:

public class Main { private static class Inner { } static void checkSynthetic (String name) { try { System.out.println (name + " : " + Class.forName (name).isSynthetic ()); } catch (ClassNotFoundException exc) { exc.printStackTrace (System.out); } } public static void main(String[] args) throws Exception { new Inner (); checkSynthetic ("com.fcc.test.Main"); checkSynthetic ("com.fcc.test.Main$Inner"); checkSynthetic ("com.fcc.test.Main$1"); } } //打印结果: com.fcc.test.Main : false com.fcc.test.Main$Inner : false com.fcc.test.Main$1 : true //编译结果,生成三个class文件: Main.class/Main$Inner/Main$1.class // $FF: synthetic class class Main$1 { }

Inner这个内部类是私有的,私有内部类。拥有内部类的类编译后内外部类两者没有关系,那么私有内部类编译后默认是没有对外构造器的(如果以上代码中在Inner手动给一个public的构造器,Main$1是不会出现的),但是我们又知道,外部类是可以引用内部类的,那么编译后,又是两个毫无关系的类,一个类没对外构造器,但另一个类确实是有对这个类的实例对象权限(这里就是重点,内部类哪怕没有public构造器,外部类都有实例化内部类对象的权限)的,这种情况下编译器就会生成一个合成类,也就是Main$1,一个什么也没有的空类(是的,什么也没有,连构造器都没有)。但到这里,仍然不明白其实现原理是怎么样的,原先以为合成类是那个内部类的副本,外部类访问内部类,在编译器认为只是和合成类交互,只是合成类只有外部类有权限访问,但是事实上,不管内部类怎么变化,合成类只是一个空的类,有点类似标记作用(真正作用却是不得而知)。

AccessibleObject类

AccessibleObject是一个普通Java类,实现了AnnotatedElement接口,但是对应AnnotatedElement的非默认方法的实现都是直接抛异常,也就是AnnotatedElement的接口方法必须由AccessibleObject的子类去实现,个人认为AccessibleObject应该设计为抽象类。AccessibleObject在JDK1.1的时候已经存在,在JDK9的时候被改进过,添加了一些新的方法,下面列举一下常用的方法:

方法 功能
void setAccessible(boolean flag)   设置实例是否可以访问,如果设置为true,可以抑制修饰符,直接进行访问  
boolean isAccessible()   返回实例是否可以访问,实际上这个值并不准确,它只有在setAccessible被调用的时候才会更新  
boolean trySetAccessible()   功能类似于setAccessible(boolean flag),返回值决定是否抑制修饰符成功  
static void setAccessible(AccessibleObject[] array, boolean flag)   setAccessible(boolean flag)的批量操作方法  

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zywspx.html