什么是反射
官方有段介绍是这么说的
Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine.
什么意思呢,就是说反射通常用于需要能够检查或修改Java虚拟机中运行的应用程序的运行时行为的程序。
不是很好懂,我们说下反射能做什么吧。
- 反射可以在运行时动态生成某个类的实例。
- 反射可以在运行时获取某个类的任何的变量并修改变量的值。
- 反射可以在运行时执行某个类的任何方法。
如何使用反射
我们针对上面的情况一一说一下如何使用。
我们先定义一个 com.reflect.Demo.java 用来做我们后续的实验。
package com.reflect;
public class Demo {
public String pubStr = "public_string";
private String priStr = "private_string";
private String getPriStr(String testParam) {
pubStr = testParam;
return priStr;
}
private String getPriStr() {
return priStr;
}
public Demo() {
}
private Demo( String priStr ) {
this.priStr = priStr;
}
@Override
public String toString() {
return "Demo{" +
"pubStr='" + pubStr + '\'' +
", priStr='" + priStr + '\'' +
'}';
}
}
在运行时动态生成某个类的实例
// 反射第一步是获取类的 class , 一般有 3 种写法
Class demoClass = Class.forName("com.reflect.Demo");
// demoClass = Demo.class;
// demoClass = new Demo().getClass();
// 获取无参构造函数
Constructor constructor = demoClass.getDeclaredConstructor();
// 设置可以访问
constructor.setAccessible(true);
// 根据构造方法创建实例
Object demo = constructor.newInstance();
// 获取有参构造函数
Constructor constructor1 = demoClass.getDeclaredConstructor(String.class);
// 设置可以访问
constructor1.setAccessible(true);
// 根据构造方法创建实例
Object demo1 = constructor1.newInstance("I am String");
下面介绍一种通用的获取某个类的实例的方法
/**
* 运用反射,通过默认的构造方法获取某个类的实例
*
* @param className
* @return
*/
public static Object getObjectInstance(String className, Object... args) {
try {
Class[] classes = new Class[args.length];
for (int i = 0; i < args.length; i++) {
classes[i] = args[i].getClass();
}
Class objClass = Class.forName(className);
Constructor constructor = objClass.getDeclaredConstructor(classes);
constructor.setAccessible(true);
return constructor.newInstance(args);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return new Object();
}
在运行时获取某个类的任何的变量并修改变量的值
下面的代码会告诉大家如何获取 Demo.java 的一个实例的变量 (priStr) 并对其赋值。
// 无参构造方法 new 的实例,里面的 priStr 值为 private_string
Demo demo = new Demo();
// 获取 demo 的 class
Class demoClass = demo.getClass();
// 获取 priStr 的 Field
Field priStrField = demoClass.getDeclaredField("priStr");
// 设置可以访问
priStrField.setAccessible(true);
// 取 priStr 的值
// 要取的是 demo 这个实例的 priStr , 所以需要传入 demo
Object priStrValue = priStrField.get(demo);
// 修改 priStr 的值
// 要修改的是 demo 这个实例, 所以需要传入 demo
priStrField.set(demo,"I am Private String");
下面介绍一种通用的获取属性的方法
/**
* 获取某个变量的值
*
* @param obj 待取值的类
* @param fieldName 待取值的变量的变量名
* @return
*/
public static Object getFieldValue(Object obj, String fieldName) {
try {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return new Object();
}
/**
* 设置某个类的某个变量的值
*
* @param obj
* @param fieldName
* @param fieldValue
* @return
*/
public static boolean setFieldValue(Object obj, String fieldName, Object fieldValue) {
try {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, fieldValue);
return true;
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return false;
}
在运行时执行某个类的任何方法
下面的代码会告诉大家如何获取 Demo.java 的一个方法(getPriStr) 并调用此方法。
// 无参构造方法 new 的实例,里面的 priStr 值为 private_string
Demo demo = new Demo();
// 获取 demo 的 class
Class demoClass = demo.getClass();
// 获取无参 getPriStr 对应的 Method
Method priStrMethod = demoClass.getDeclaredMethod("priStr");
// 设置可以访问
priStrMethod.setAccessible(true);
// 调用此方法
Object priStr = priStrMethod.invoke(obj);
// 获取有参 getPriStr 对应的 Method
Method priStrMethod1 = demoClass.getDeclaredMethod("priStr",String.class);
// 设置可以访问
priStrMethod1.setAccessible(true);
// 调用此方法
Object priStr1 = priStrMethod1.invoke(obj,"I am testParam");
下面介绍一种通用的调用对象的方法
/**
* 调用某个方法
* @param obj
* @param methodName
* @param args
* @return
*/
public static Object invokMethod(Object obj, String methodName, Object... args) {
try {
Class[] classes = new Class[args.length];
for (int i = 0; i < args.length; i++) {
classes[i] = args[i].getClass();
}
Method method = obj.getClass().getDeclaredMethod(methodName, classes);
method.setAccessible(true);
method.invoke(obj,args);
return method.invoke(obj, args);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return new Object();
}