@Author: Patrilic @Time: 2020-3-18 17:43:11
反射是Java的一个高级特性,指在 运行状态中 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,创建实例,修改类成员变量等等。 这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
| 类名 | 用途 |
|---|---|
| Class类 | 类的实体,在运行的Java应用程序中表示类和接口 |
| Method类 | 类的方法 |
| Construct类 | 类的构造方法 |
| Field类 | 类的成员变量 |
获取类的方式通常有三种
Class runtimeClass1 = Class.forName(className); Class runtimeClass2 = java.lang.Runtime.class; Class runtimeClass3 = ClassLoader.getSystemClassLoader().loadClass(className);
需要注意的是,在获取数组类型的Class对象时,需要使用特殊的Java描述符
Class<?> doubleArray = Class.forName("[D");
Class<?> cStringArray = Class.forName("[[Ljava.lang.String;");
首先跳到 java.lang.Runtime 的源码处,可以观察到Runtime类的构造方法是private属性的,也就是说不允许其他人创建实例。
也就是说,在没有 import java.lang.Runtime 的时候,我们是不能够去new一个新的Runtime对象的
反射机制提供了两种方法可以获取类的构造方法:
获取Constuct后,使用 constructor.newInstance() 实例化
当我们没有访问构造方法权限时我们应该调用constructor.setAccessible(true)修改访问权限就可以成功的创建出类实例了
获取当前类所有的成员方法:
Method[] methods = runtimeClass1.getDeclaredMethods();
获取当前类指定的成员方法:
Method method = clazz.getDeclaredMethod("方法名");
通过method.invoke可以调用方法:
method.invoke(方法实例对象, 方法参数值,多个参数值用","隔开);
method.invoke的第一个参数必须是类实例对象,如果调用的是static方法那么第一个参数值可以传null,因为在java中调用静态方法是不需要有类实例的,因为可以直接类名.方法名(参数)的方式调用
获取当前类的所有成员变量:
Field fields = clazz.getDeclaredFields();
获取当前类指定的成员变量:
Field field = clazz.getDeclaredField("变量名");
获取当前类的所有成员变量:
Field fields = clazz.getDeclaredFields();
获取当前类指定的成员变量:
Field field = clazz.getDeclaredField("变量名");
当我们没有修改的成员变量权限时可以使用: field.setAccessible(true)的方式修改为访问成员变量访问权限
修改final关键字修饰的变量时:
// 反射获取Field类的modifiers
Field modifiers = field.getClass().getDeclaredField("modifiers");
// 设置modifiers修改权限
modifiers.setAccessible(true);
// 修改成员变量的Field对象的modifiers值
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
// 修改成员变量值
field.set(类实例对象, 修改后的值);
package com.patrilic.reflect;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class RuntimeClass {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
String className = "java.lang.Runtime";
Class runtimeClass1 = Class.forName(className);
Class runtimeClass2 = java.lang.Runtime.class;
Class runtimeClass3 = ClassLoader.getSystemClassLoader().loadClass(className);
System.out.println(runtimeClass1);
System.out.println(runtimeClass2);
System.out.println(runtimeClass3);
Constructor constructor = runtimeClass1.getDeclaredConstructor();
constructor.setAccessible(true);
// 创建Runtime类示例,等价于 Runtime rt = new Runtime();
Object runtimeInstance = constructor.newInstance();
// 获取Runtime的exec(String cmd)方法
try {
Method runtimeMethod = runtimeClass1.getMethod("exec", String.class);
Process process = (Process) runtimeMethod.invoke(runtimeInstance, "open -a /System/Applications/Calculator.app");
} catch (Exception e) {
System.out.println(e);
}
}
}