今天说起的这个东西,有点厉害了,虽然你不了解它也不影响你写程序,但是,它却悄悄的一直在你的左右。
人常说,一个成功男人背后,一定会有位伟大的女人。像Struts、Spring、Hibernate等等的Java EE框架如此的成功和神奇,背后,就是有位像Java类反射的“女人”。
现,让我们来了解和学学这个“女人”:
我们都知道,JVM是通过调用由.java编译成.class的对象文件来执行的,这个过程大致可以这样描述:
类装载器ClassLoader将.class对象加载到内存中,在内存中找到main方法开始执行,在执行的过程中,通过动态加载机制还会把与其相关联的.class加载到内存中并运行。
.class文件在Java类中被描绘成java.lang.Class,其中的属性和方法分别对应java.lang.reflect.Field和java.lang.reflect.Method,构造函数呢,则有java.lang.reflect.Constructor这个类对应。如此这样,我们自然而然的就可以通过程序化的方式来操作Class对象。
OK,看个例子先:
package com.cui.hourse.reflectDemo;
class Dog {
private String name;
private int age;
public Dog() {
}
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
public void show() {
System.out.println("The dog's name is: " + name + ",age is: " + age);
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
很简单的,一个POJO对象,里面的内容不做过多介绍,来看看怎么样通过反射来实例化:
package com.cui.hourse.reflectDemo;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectDemo {
/**
* 通过反射机制实例化一个Dog实例
*
* @return Dog
*/
public static Dog initDogByReflectionMethod() throws Throwable {
//获取当前线程,指定Dog类的全限定名(必须是全限定名),装载该Class的类反射实例
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class cls = loader.loadClass("com.cui.hourse.reflectDemo.Dog");
//获取默认构造函数Constructor,并通过该构造函数实例化Dog对象
Constructor consor = cls.getDeclaredConstructor();
Dog dog = (Dog) consor.newInstance();
//通过Class对象的getMethod方法,获取方法对象Method,
//第一个参数为方法名,第二个参数为方法参数类型
Method setName = cls.getMethod("setName", String.class);
//通过invoke方法调用目标类方法
//第一个参数为目标类对象实例,第二个参数为目标类对象方法的入参
setName.invoke(dog, "xiao bai");
Method setAge = cls.getMethod("setAge", int.class);
setAge.invoke(dog, 2);
return dog;
}
public static void main(String[] args) throws Throwable {
Dog dog = initDogByReflectionMethod();//实例化一个Dog对象
dog.show();
}
}
运行,最后程序结果正如我们所期望的:
The dog's name is: xiao bai,age is: 2
与我们自己new一个对象的结果完全相同,这说明,我们完全可以通过编程的方式操作Class所提供的各项功能,这和直接通过构造函数和方法调用类功能的效果是一致的,只不过一个是简单调整,别一个是直接调用而已。