@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); } } }