java 反射用一句话来说明,即是 java 语言提供的一系列 api,用来在运行时检测和修改类、方法、接口等运行时对象。
三个关于 java reflection 的关键点:
所有有关 reflection 功能的类都定义在 java.lang.reflect 这个包内
通过 reflection 使用者可以指导给定对象的类信息,以及与这个类绑定的所有方法的信息
通过使用 reflection 的相关接口,使用者可以在运行时调用和修改与指定对象相关类的方法,而不需要事先知道有关这个对象类的详细信息
下面通过一个详细的例子来解释 reflection 的功能,例子中涉及到 reflection 包中十分重要的三个类:
Class 类,通过指定对象的 getClass 方法调用,可以得到指定对象的类
Constructors 类,通过对指定对象类 getConstructors 方法调用,可以得到指定对象类的构造函数
Methods 类,通过对指定对象类 getMethods 方法调用,可以得到指定对象类的所有公共方法列表
// 一个典型的java reflection使用示例
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Constructor;
// 声明Test类,后面用来在其它类中展示reflection用法
class Test
{
// 创建私有字符串变量s
private String s;
// 创建构造函数
public Test() { s = "Test"; }
// 创建无参公共方法method1
public void method1() {
System.out.println("The string is " + s);
}
// 创建带整形参数n的公共方法method2
public void method2(int n) {
System.out.println("The number is " + n);
}
// 创建一个私有方法
private void method3() {
System.out.println("Private method invoked");
}
}
class Demo
{
public static void main(String args[]) throws Exception
{
// new一个Test类的实例,以供后面reflection接口使用
Test obj = new Test();
// 从obj中获取对应类,并通过getName方法获取类名称
Class cls = obj.getClass();
System.out.println("The name of class is " +
cls.getName());
// 从cls实例中获取构造函数实例
Constructor constructor = cls.getConstructor();
System.out.println("The name of constructor is " +
constructor.getName());
System.out.println("The public methods of class are : ");
// 从cls实例中获取其所有公共方法列表
Method[] methods = cls.getMethods();
// 打印公共方法名称
for (Method method:methods)
System.out.println(method.getName());
// 传入名称和对应方法参数,获取类的方法
Method methodcall1 = cls.getDeclaredMethod("method2",
int.class);
// 类方法独立与实例obj本身进行调用
methodcall1.invoke(obj, 19);
// 传属性名获得类的属性实例
Field field = cls.getDeclaredField("s");
// 改变属性访问权限为公共
field.setAccessible(true);
// 调用属性实例field的set方法,传入obj来修改obj的属性值
field.set(obj, "JAVA");
// 传入方法名称获取方法实例
Method methodcall2 = cls.getDeclaredMethod("method1");
// 如需通过obj,调用Method类实例,当然obj还是需要作为参数传入
methodcall2.invoke(obj);
// 传入方法名获取Test的私有方法method3
Method methodcall3 = cls.getDeclaredMethod("method3");
// 改变method3的访问控制为公开
methodcall3.setAccessible(true);
// 调用已改为公开访问的method3
methodcall3.invoke(obj);
}
}
复制代码
运行输出:
The name of class is Test
The name of constructor is Test
The public methods of class are :
method2
method1
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll
The number is 19
The string is JAVA
Private method invoked
复制代码
从上面的程序输出中可以看出:
只要知道某个类的方法名称和其对应的参数类型,就可以通过 getDeclareMethod 方法获取对应 reflection Method 方法实例,并使用 invoke 方法来动态调用这个 Method 实例。用法如下:
Class.getDeclareMethod(name, parametertype)
name - 需要实例化的方法名称
parametertype - 方法对应的参数类型列表
复制代码
如果要调用“反射”出来的方法,可以使用 Method 示例的 invoke 方法:
Method.invoke(Object, parameter)
复制代码
通过 reflection 的使用,可以改变原来类方法或者属性的访问权限,如上例所示。
小结:
通过上面的例子,可以了解到通过使用 reflection,可以很方便的在应用中集成未知的用户定义类的各项功能,也能更加方便的调试现有程序,当然 reflection 的使用也增加了程序本身对外信息暴露的风险。
评论