目录
反射
通过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。
反射之所以被称为框架的灵魂,主要是因为它赋予了我们在运行时分析类以及执行类中方法的能力。
反射机制的优缺点
- 优点 : 可以让代码更加灵活、为各种框架提供开箱即用的功能提供了便利。
- 缺点 :在运行时有了分析操作类的能力,这同样也增加了安全问题。比如可以无视泛型参数的安全检查(泛型参数的安全检查发生在编译时)。反射的性能也要稍差点。
获取 Class 对象的四种方式
如果我们动态获取到这些信息,我们需要依靠 Class 对象。Class 类对象将一个类的方法、变量等信息告诉运行的程序。Java 提供了四种方式获取 Class 对象:
知道具体类的情况下
Class clazz = TargetObject.class;
此方式获取 Class 对象不会进行初始化
通过 Class.forName()传入类的全路径获取
Class clazz = Class.forName("com.example.TargetObject");
会执行静态代码块
通过对象实例instance.getClass()获取
TargetObject o = new TargetObject();
Class clazz = o.getClass();
不进行初始化
通过类加载器xxxClassLoader.loadClass()传入类路径获取
Class clazz = ClassLoader.loadClass("com.example.TargetObject");
通过类加载器获取 Class 对象不会进行初始化,意味着不进行包括初始化等一系列步骤,静态代码块和静态对象不会得到执行
反射的一些基本操作
class TargetObject{
private int value = 999;
public TargetObject() {
value = 111;
}
public void publicMethod(String s) {
System.out.println(s);
}
private void privateMethod() {
System.out.println("value is " + value);
}
}
public class Main{
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
/**
* 获取 TargetObject 类的 Class 对象并且创建 TargetObject 类实例
*/
Class<?> targetClass = Class.forName("com.example.TargetObject");
TargetObject targetObject = (TargetObject) targetClass.newInstance();
/**
* 获取 TargetObject 类中定义的所有方法
*/
Method[] methods = targetClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
/**
* 获取指定方法并调用
*/
Method publicMethod = targetClass.getDeclaredMethod("publicMethod",
String.class);
publicMethod.invoke(targetObject, "hello");
/**
* 调用 private 方法
*/
Method privateMethod = targetClass.getDeclaredMethod("privateMethod");
//为了调用private方法我们取消安全检查
privateMethod.setAccessible(true);
privateMethod.invoke(targetObject);
/**
* 获取指定参数并对参数进行修改
*/
Field field = targetClass.getDeclaredField("value");
//为了对类中的参数进行修改我们取消安全检查
field.setAccessible(true);
field.set(targetObject, 666);
//检查修改的值
privateMethod.invoke(targetObject);
}
}