java反射

什么是java反射

Java反射是Java的一种特性,它可以让程序在运行时获取自身的信息,并且动态地操作类或对象的属性、方法和构造器等。Java反射指的是在Java程序运行状态中,对于任何一个类,都可以获得这个类的所有属性和方法;对于给定的一个对象,都能够调用它的任意一个属性和方法。这种动态获取类的内容以及动态调用对象的方法称为反射机制。

反射在反序列化漏洞中的应用:

定制需要的对象

通过invoke调用除了同名函数以外的函数

通过Class类创建对象,引入不能序列化的类

Java反射机制

获取Class对象的四种方式

java.lang.Class类是反射的基础,存放对应对象的运行时的信息。在Java程序运行时,JVM为所有类型维护一个java.lang.Class对象,即每种类型的Class对象只有一个。Class对象是我们进行反射操作的入口:

1
2
3
//方式一:通过该实例变量提供的getClass()方法获取
//Object.getClass()
Class studentClass = student.getClass();
1
2
3
//方式二:直接通过一个class的静态变量class获取:
//T.class
Class studentClass = Student.class;
1
2
3
4
5
6
7
8
//方式三:知道一个class的完整类名,可以通过静态方法Class.forName()获取
//static Class<?> Class.forName
try {
Class studentClass_3 = Class.forName("lic.reflect.Student");
System.out.println("Class.forName = " + studentClass);
} catch (ClassNotFoundException exception) { //此方式会抛出 ClassNotFoundException 异常
exception.printStackTrace(System.err);
}
1
2
3
4
5
6
7
//方式四:通过 ClassLoader
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class<?> c = classLoader.loadClass("java.lang.String");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

在Class对象中一般有三类信息:构造方法Constructor、成员方法Method、成员变量Field。

获取构造方法Constructor

Class类中用于获取构造方法:

Constructor<?>[] getConstructors() 返回所有公共构造方法对象的数组(只能获取public的构造方法)

Constructor<?>[] getDeclaredConstructors() 返回所有构造方法对象的数组(所有构造方法,包含private)

Constructor<T> getConsturctor(Class<?>... parameterTypes) 返回单个指定的公共构造方法

Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回单个指定的构造方法

declared的方法和不带declared的方法的区别:

  • 不带 Declared的方法支持取出包括继承、公有(Public) 但不包括有(Private)的构造函数

  • Declared的方法是支持取出包括公共(Public)、保护(Protected)、默认(包)访问和私有(Private)的构造方法,但不包括继承的构造函数

    • T newInstance(Object... initargs) 根据指定的构造方法创建对象
    • setAccessible(boolean flag) 设置是否取消访问检查,设置为 true 表示取消访问检查,可以提高反射效率

获取成员变量Field

Class类中用于获取成员变量的方法:

Field[] getFields() 返回此类和父类中所有public的成员变量
Field[] getDeclaredFields() 返回此类中所有的成员变量,不包括父类
FIeld getField(String name) 从此类和父类中查找对应的public成员变量并返回
Field getDeclaredField(String name) 在此类中查找指定的成员变量并返回

Field 类中用于设置和获取成员变量的方法:

void set(Object obj, Object value) 设置 obj 对象中的此成员变量设置为 value
Object get(Object obj) 获取 obj 对象中的此成员变量
String getName() 获取此成员变量的名称
Class<?> getType() 获取此成员变量的类型
int getModifiers() 获取此成员变量的修饰符(即 private volatile之类的),通过 Modifier 类方便查询

获取成员方法Method:

Class 类中用于获取成员变量的方法:

Method[] getMethdos() 返回所有 public 成员方法的对象,包括继承的
Method[] getDeclaredMethods() 返回此类中所有成员方法对象的数组
Method getMethod(String name, Class<?>... parameterTypes) 查找此类及父类中指定的 public 成员方法
Method getDeclaredMethod(String name, Class<?>... parameterTypes) 查找并返回单个成员方法
Method 类中的常用方法:

Object invoke(Object obj, Object... args) 调用 obj 对象上的这个方法
Class getReturnType() 返回这个方法的返回值类型
Type getGenericReturnType() 返回这个方法的泛型返回值类型
Class[] getParameterTypes() 返回这个方法的参数类型
Type[] getGenericParameterTypes() 返回这个方法的参数的泛型信息
Annotation[] getAnnotations() 返回这个方法上的注解

其他:

当我们要获取私有构造方法、成员方法、成员变量时要修改权限。

1
2
3
4
5
6
//构造方法
declaredConstructor.setAccessible(true);
//成员方法
declaredMethod.setAccessible(true);
//成员变量
declaredField.setAccessible(true);

示例:

1
2
3
4
5
6
7
8
9
10
11
12
public class AAA {
private String name ="piiick";

private int age = 18;

private AAA(){}


private void SayHello(){
System.out.println("Hello, i'm "+name+" and "+age);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Main {
public static void main(String[] args) throws Exception {
//获取Class对象
Class personClass = AAA.class;
//获取构造方法Constructor
Constructor declaredConstructor = personClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
//根据指定的构造方法创建对象
AAA aaa = (AAA)declaredConstructor.newInstance();
//获取成员变量Field(name)并且赋值给name
Field declaredField = personClass.getDeclaredField("name");
declaredField.setAccessible(true);
Object name = declaredField.get(aaa);
//获取成员变量Field(age)并且修改age的值为23
Field ageField = personClass.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(aaa, 23);
//获取成员方法Method(sayHello)
Method sayHello = personClass.getDeclaredMethod("SayHello");
sayHello.setAccessible(true);
//调用 `aaa` 对象上的这个方法
sayHello.invoke(aaa);
}
}

java反射
http://example.com/2024/08/01/反射/
作者
piiick
发布于
2024年8月1日
许可协议