Java提供“执行期间让你得以找出对象及class相关信息”。包括两种形式:第一种是“传统的”RTTI(Run-Time Type Identification)机制,它假设你在编译期和执行期拥有所有型别信息。第二种是reflection机制,允许你在执行期间找出和class相关的信息。
Class对象
执行期间采用的是隶属Class的特别的对象来表示型别信息。Class对象内包含与class相关的各种信息。程序中的每个class都有一个相应的Class对象。换句话说,每写一个新的class并编译完成,就会产生一个Class对象存储与相同的.class文件内。执行期间当你想要产生该class的对象时,Java虚拟机(JVM)便会先检查该型别的Class对象是否已被装载。如果尚未装载,JVM会根据名称找到.class文件并装载它。因此Java程序启动时并不会将整个程序都转载。一旦某个型别的Class对象已被装载内存,它就可以被用来产生该型别的所有对象。
Class.forName("Student");
这是Class(所有Class对象皆属此一类型)的一个static成员。Class对象就像其它对象一样,可以取其reference并加以操作(这也是装载器所做的工作)。取得Class object reference的方法之一便是调用forName(),它接受一个字符串作为引数,字符串内含某个“你想取其Class对象”的reference的文本表达式。它会返回一个Class reference。
Student.class;
Java通过所谓的“类字面量”提供第二种方式来取得“指向Class对象”的reference。这么做不仅简单,也更安全,因此检查动作在编译期就进行了。由于它不用调用任何函数,所以也更有效率。
所有基本型别的外覆类都有一个名为TYPE的标准数据,能够产生一个reference,指向相应的基本型别的Class对象。例如 boolean.class 可以使用 Boolean.Type 来获取。
Reflectoin(反射)
Java提供一个java.lang.reflect程序库,其中含有Field、Method、Constructor等class。这些型别的对象是由JVM于执行期产生,用来代表未知class内的相应成员。可以使用Constructor来产生新对象,使用get()和set()来读取或设定相应于Field对象的数据值,也可以使用invoke()来调用相应于Method对象的函数。也可以调用getFields()、getMethods()、getConstructors()等,它们会传回数组,内含“代表数据成员、函数、构造函数”的对象。因此,即使完全不认识某个对象,编译器无法获得其任何信息,仍然可以在执行期找出其完整的class信息。
当使用reflection来处理型别未知的对象,JVM会先检视该对象,检查它是否属于某个class。不过,稍后在JVM开始对它进行一些动作之前,得先将Class对象装载,因此JVM必须能够取得该型别所对应的.class文件,不论是在本机还是跨网络获取。RTTI的差别在于,编译器在编译期即开启检查.class文件,但如果采用reflection机制,编译期并不会取用.class文件,它会由执行期环境加以开启和检验。
try {
Class c = Class.forName("com.cage.home.io.ArrayUtil");
Constructor con = c.getConstructor();
Object co = con.newInstance();
Method methodCheck = c.getMethod("check");
methodCheck.invoke(co);
} catch (Exception e) {
System.out.println("Exception--");
System.out.println(e.getClass());
System.out.println(e.getMessage());
}
forName()中的字符串必须是全路径的类名称。当invoke一个static方法时,对象参数传null即可。另外,通过Class直接进行newInstance()的方法已被deprecated,需要使用constructor来创建Class的对象。
网友评论