转载

Java Refection

@Author: Patrilic @Time: 2020-3-18 17:43:11

Java Refection

0x00 前言

反射是Java的一个高级特性,指在 运行状态中 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,创建实例,修改类成员变量等等。 这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

0x01 相关类

类名 用途
Class类 类的实体,在运行的Java应用程序中表示类和接口
Method类 类的方法
Construct类 类的构造方法
Field类 类的成员变量

Get Class

获取类的方式通常有三种

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;");

Get Construct

首先跳到 java.lang.Runtime 的源码处,可以观察到Runtime类的构造方法是private属性的,也就是说不允许其他人创建实例。

Java Refection

也就是说,在没有 import java.lang.Runtime 的时候,我们是不能够去new一个新的Runtime对象的

反射机制提供了两种方法可以获取类的构造方法:

  • runtimeClass1.getDeclaredConstructor
  • runtimeClass1.getConstructor // 不能获取private方法

获取Constuct后,使用 constructor.newInstance() 实例化

当我们没有访问构造方法权限时我们应该调用constructor.setAccessible(true)修改访问权限就可以成功的创建出类实例了

Get Method

获取当前类所有的成员方法:

Method[] methods = runtimeClass1.getDeclaredMethods();

获取当前类指定的成员方法:

Method method = clazz.getDeclaredMethod("方法名");

通过method.invoke可以调用方法:

method.invoke(方法实例对象, 方法参数值,多个参数值用","隔开);

method.invoke的第一个参数必须是类实例对象,如果调用的是static方法那么第一个参数值可以传null,因为在java中调用静态方法是不需要有类实例的,因为可以直接类名.方法名(参数)的方式调用

Get Field

获取当前类的所有成员变量:

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(类实例对象, 修改后的值);

0x02 反射java.lang.Runtime

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

Java Refection

原文  https://patrilic.top/2020/03/18/Java Reflection/
正文到此结束
Loading...