杜叔强
摘 要:反射是Java语言中的一种重要的编程机制;总结了Java语言中反射的原理,以及反射相关类的获取方式,并总结了反射机制的几点应用。
关键词:反射机制 Class Constructor Field Method
1反射的概念
Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时通过反射API取得任何一个已知名称的类的内部信息,包括其访问修饰符、父类、实现的接口,也包括属性和方法的所有信息,并可在运行时改变属性值或进行方法调用。Java反射机制容许程序在运行时加载、探知、使用编译期间完全未知的类。也就是说,Java可以加载一个运行时才得知名称的类,并且获得其完整结构信息,这种动态获取信息以及动态调用对象的成员的功能称为java语言的反射机制[1]。
2反射的原理
Java反射机制的实现要借助于4个类:Class,Constructor,Field,Method;其中Class代表的是类对象,Constructor是类的构造器对象,Field是类的属性对象,Method是类的方法对象,通过这四个对象我们可以粗略的看到一个类的各个组成部分。其中最核心的就是Class类,它是实现反射的基础。Class类的实例就是某个类的描述信息。Class类的实例表示正在运行的Java应用程序中的类和接口。
Class没有公共构造方法。Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的。JVM在程序第一次主动使用某个类的时候,才会去加载该类。也就是说,JVM并不是在一开始就把一个程序所有的类都加载到内存中,而是到用的时候才把它加载进来,而且只加载一次。当JVM加载某个类时,会到本地磁盘去找到这个类的字节码文件,然后将这个字节码文件加载到JVM内存中,并且在内存堆区创建这个类的Class对象。注意这个不是new出来的对象,而是类的类型描述对象,每个类只有一个Class对象,作为类的数据结构的接口。JVM创建对象前,会先检查类是否加载,寻找类对应的Class对象,若类已加载好,则为待创建对象分配内存。有了类型信息描述对象Class对象,就可以获取类的属性,方法等信息。
3 Class对象的获取
有三种方式可以获取Class对象[2]。
(1)通过类.class属性获得。任何数据类型都有一个“静态”的class属性。Java在编译一个类文件时,会为该类动态地添加一个公有的静态常量属性class,这个属性记录了该类的相关信息,即类型描述信息,它是Class类的实例。
(2)通过对象.getClass()方法获得。任何对象都可以调用getClass()返回表示此对象运行时类的Class对象。当得到一个对象引用而不知道所属的类时,就可以用此方法得到该对象所属类的Class对象。
(3)通过Class.formName()静态方法获得。Java的Class提供了静态方法formName(),此方法显示地加载指定类,并返回被加载类的Class对象。
4 Constructor对象的获取
Constructor类的对象用于描述类的单个构造方法。Class对象提供了四个方法可以获取Constructor對象。
(1)getConstructor(Class parameterTypes…)获取指定参数类型的公有Constructor对象。
(2)getConstructors()获取指定类的公有构造方法描述对象Constructor列表。
(3)getDeclaredConstructor(Class parameterTypes…)获取指定参数类型的构造方法描述对象。
(4)getDeclaredConstructors()获取指定类的所有构造方法描述对象列表。
5 Method对象的获取
Method类的对象用于描述类的单个方法(不包括构造方法)。可以通过Method类来获取方法的访问权限、参数类型、返回值类型等信息,并且可以通过获取的Method对象来动态执行方法。Class对象提供了四个方法可以获取Method对象。
(1)getMethod(String name,Class parameterTypes…)获取指定名称和参数类型的公有方法描述对象。
(2)getMethods()获取公有的方法描述对象列表。
(3)getDeclaredMethod(String name, Class parameterTypes…)获取指定名称和参数类型的方法描述对象。
(4)getDeclaredMethods()获取类本身定义的所有方法描述对象。
6 Field对象的获取
Field类的对象用于描述类的单个属性。可以通过Field对象来获取属性的访问权限、属性类型等信息,并且可以通过获取的Field对象来动态地修改属性值。Class对象也提供了四个方法可以获取Field对象。
(1)getField(String name)获取指定名称的公有Field对象。
(2)getFields()获取指定类的公有属性描述对象Field列表。
(3)getDeclaredField(String name)获取指定名称的Field对象。
(4)getDeclaredFields()获取指定类的所有属性描述对象Field列表。
7反射的应用
(1)运行时类型识别
Class对象的isInstance()方法其原型是public boolean isInstance(Object obj),这个方法用来判定指定的对象是不是类的实例。例如从一个容器中取得了对象后,就可以判定这个对象的所属的类。
(2)获取资源文件的URL
Class对象的getResource()方法其原型是public URL getResource(String name),此方法可以返回与给定类相关的指定名称的资源URL。如果程序中用到图片、音频等资源,可以将这些资源放到相关类字节码文件相同目录,便于程序打包成jar文件。
(3)动态获取类型信息
在程序中可以通过反射显式加载指定类,通过反射实例化类,还可以通过反射执行方法,修改属性值和访问权限等操作。
8小结
Java中反射机制很实用,灵活使用反射能让我们代码更加灵活。但是反射也有缺点,反射包括了一些动态类型,所以 JVM 无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被执行的代码或对性能要求很高的程序中使用反射[3]。
参考文献:
[1]Java基础之—反射[EB/OL].[2018-03-17].http://blog.csdn.net/sinat_38259539/article/details/71799078
[2]徐传运 张杨.Java高级程序设计[M].北京:清华大学出版社,2014.
[3]粗浅看 java反射机制[EB/OL].[2018-03-17.http://blog.csdn.net/wsl211511/article/details/51605655