概述
java的反射技术允许我们在程序运行时动态创建一个指定的类,并访问这个类中声明的字段和方法以及注解,这种动态获取类的信息以及动态调用对象的方法的功能称为java语言的反射机制。
JDK提供的用于java反射技术的几个主要类有:ClassLoader、Class、Method、Field、Constructor等,通过这些反射类就可以间接调用目标Class的各项功能。
下面以一个简单实例进行演示:
要通过反射来访问的类:TestVo
package cn.qing.reflect;
public class TestVo {
private String name;
private Integer age;
/**
* 一个无参的构造方法
*/
public TestVo(){}
/**
* 一个带有参数的构造方法
* @param name
* @param age
*/
public TestVo(String name,Integer age)
{
this.name = name;
this.age = age;
}
public String otherMethod(String info)
{
System.out.println("message:"+info);
return "test\t"+ info;
}
@Override
public String toString() {
return "TestVo [age=" + age + ", name=" + name + "]";
}
/**************set/get*****************/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
通过反射技术访问TestVo的测试类:TestReflect
package cn.qing.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class TestReflect {
public static void main(String[] args) {
TestReflect reflect = new TestReflect();
try {
TestVo testVo = reflect.getTestVo();
testVo.otherMethod("info");
System.out.println(testVo.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
public TestVo getTestVo()throws Exception
{
//使用当前线程来获取ClassLoader
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
//使用装载器来装载指定的Class,此处为类的全路径
Class clazz = classLoader.loadClass("cn.qing.reflect.TestVo");
//获取类的带有参数的构造器,并实例它,也可以获取无参的构造器
Constructor constructor = clazz.getConstructor(String.class,Integer.class);
TestVo testVo = (TestVo)constructor.newInstance("dog",20);
//获取类声明的方法
Method method = clazz.getDeclaredMethod("toString", null);
System.out.println(method.invoke(testVo, null));
//获取类声明的字段
Field field = clazz.getDeclaredField("name");
//如果想访问私有属性或方法,可以设置setAccessible为true
field.setAccessible(true);
field.set(testVo, "cat");
return testVo;
}
}
程序输出的结果为:
TestVo [age=20, name=dog]
message:info
TestVo [age=20, name=cat]
第一句输出是使用method.invoke()方法来执行TestVo中的toString()
第二个是通过反射构造的实体TestVo类进行调用otherMethod()方法输出
第三个是在得到成员变量name的反射类Field后重新设置其值为"cat",最后在调用toString()方法输出的
上面的示例可以看出,我们可以通过发射来得到类的构造器,并且通过构造器实例化一个类,也可以得到类中申明的方法,并通过Method.invoke()来回调方法,还可以获得类的成员变量,并为成员变量负值。
java反射的主要类描述:
通过Java反射技术可以从Class对象中获取构造函数、成员变量、成员方法等类元素的反射对象,并以编程的方式通过这些反射对象对反射类进行操作。
这些反射对象类在java.reflect包中定义,下面是最主要的三个反射类:
Constructor:类的构造函数反射类,通过Class#getConstructors()方法可以获得类的所有构造函数反射对象组。可以使用getConstructor(Class<?>... parameterTypes)来获取指定参数的构造器,使用Constructor类的newInstance(Object... initargs)方法来实例化一个对象。
Method:类方法的反射类。通过Class#getMethod(String name,Class<?> .... parameterType)来得到指定的类成员方法,第一个参数name对应的是方法名,第二个参数对应的方法的多个入参的参数类型,通过这种方式只能访问的是类的公共成员方法(public),不能访问其它private和protected的方法。
通过Class#getDeclaredMethod(String name,Class<?> .... parameterType)可以访问该类中任何已经申明的方法,但是如果想访问private或protected的方法,需要在得到该Method以后,设置Method的setAccessible(true),这样才能够正常访问私有方法。
在得到Method对象以后可使用该类的invoke(Object obj, Object... args)方法来执行该Method。
Method中还有很多用于获取类方法更多信息的方法:
1、Class<?> getReturnType() 返回该Method的返回值类型
2、getAnnotation(Class<T> annotationClass) 返回该Method方法上申明的annotationClass注解。
3、getDeclaredAnnotations() 得到该Method上申明的所有注解。
4、TypeVariable<Method>[] getTypeParameters() 得到该方法的入参类型数组
5、 Class<?>[] getExceptionTypes() 得到该方法的异常数组。
Field:类的成员变量的反射类。通过Class#getDeclaredFields()方法可以获取该Class中已申明的所有成员变量(包括public及private的),使用Class#getDeclaredField(String name)来返回指定名称的成员变量,如果想访问私有的成员变量,可以在得到Field类以后设置setAccessible(ture),这样就可以正常访问私有成员变量。也可以通过Class#getFields()以及Class#getField(String name)来获取Class中已申明的公共成员变量。