前言

​ 反射是Java中一种动态(运行时),通过反射可以在java动态运行时,对于任意一个类,对象可以通过反射获取到他的类,类可以通过反射拿到所有方法(包括私有),动态获取信息,以及动态调用对象的方法的功能称为java语言的反射机制。

反射的具体使用步骤

在调用Java反射机制,主要步骤包括:

  • 获取 目标类型的Class对象.
  • 通过 Class 对象分别获取Constructor类对象、Method类对象 & Field 类对象.
  • 通过 Constructor类对象、Method类对象 & Field类对象分别获取类的构造函数、方法&属性的具体信息,并进行后续操作.

反射获取类的class对象

要想使用反射,我们首先需要获得代操作的类所对应的Clas对象。

1.常用的获取Class对象有四种方法:

  • 使用Class类的静态方法
1
Class clz = Class.forName("java.lang.String");
  • 使用类的.class语法
1
Class clz = String.class;
  • 使用对象的getClass()方法
1
2
String str = new String("Hello");
Class clz = str.getClass();
  • Type语法
1
2
Class<?> classType = Boolean.TYPE; 
System.out.println(classType);

反射创建类对象

常用两种方法:

  • 通过 Class 对象的 newInstance() 方法,只能使用默认的无参数构造方法。
1
2
Class clz = pen.class;
Pen pen = (pen)clz.newInstance();
  • 通过 Constructor 对象的 newInstance() 方法,可以选择特定的构造方法。
1
2
3
Class clz = pen.class;
Constructor constructor = clz.getConstructor();
Pen pen = (Pen)constructor.newInstance();

反射获取并调用类的构造函数(Constructor)

1.获取所有公有构造函数
1
2
3
Constructor[] conArray = clazz.getConstructors();
for(Constructor c : conArray){
System.out.println(c);
2.获取所有的构造函数(包括:私有、受保护、默认、公有)
1
2
3
4
conArray = clazz.getDeclaredConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
3.获取公有、无参的构造函数
1
2
3
Constructor con = clazz.getConstructor(null);
System.out.println("con = " + con);
Object obj = con.newInstance();

反射获取并调用类的成员方法(Method)

1.反射有参数方法
1
2
3
4
5
Class a = Class.forName("org.xiaopan.fanshe.Pen");
Pen pen =(Pen) a.newInstance();
public String[] b(String[] b)
Method m = a.getMethod("b",String[].class);//获取方法,需要指定要获取的方法名
String[] strs = (String[]) m.invoke(pen, new Object[]{new String[]{"str1","str2","str3"}}); //使用new Object[]{}形式传入
2.反射无参数方法
1
2
3
4
5
Class a = Class.forName("org.xiaopan.fanshe.Pen");
Pen pen =(Pen) a.newInstance();
public void a()
Method m = a.getMethod("a", null);
m.invoke(pen,null);
3.反射静态方法
1
2
3
4
Class a = Class.forName("org.fanshe.test.Pen");
public static void c()
Method m = a.getMethod("c");
m.invoke(null); //静态方法,直接调用,类对象传入null即可。

反射获取类的成员属性&赋值(Field)

1.反射公共属性

通过Class对象的etFields() 方法获取 Class 类的属性。只能获取公有属性。

1
2
3
4
5
Class clz = Pen.class;
Field[] fields = clz.getFields();
for (Field field : fields) {
System.out.println(field.getName());
}
2.反射私有属性

通过Class 对象的 getDeclaredFields() 方法则可以获取包括私有属性在内的所有属性。

1
2
3
4
5
Class clz = Pen.class;
Field[] fields = clz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName());
}

反射调用Runtime,getRuntime执行本地代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 获取Runtime类对象
Class runtimeClass1 = Class.forName("java.lang.Runtime");

// 获取构造方法
Constructor constructor = runtimeClass1.getDeclaredConstructor();
constructor.setAccessible(true);

// 创建Runtime类示例,等价于 Runtime rt = new Runtime();
Object runtimeInstance = constructor.newInstance();

// 获取Runtime的exec(String cmd)方法
Method runtimeMethod = runtimeClass1.getMethod("exec", String.class);

// 调用exec方法,等价于 rt.exec(cmd);
Process process = (Process) runtimeMethod.invoke(runtimeInstance, cmd);

// 获取命令执行结果
InputStream in = process.getInputStream();

// 输出命令执行结果
System.out.println(IOUtils.toString(in, "UTF-8"));

总结

​ Java反射机制是Java动态性中最为重要的体现,利用反射机制我们可以轻松的实现Java类的动态调用。Java的大部分框架都是采用了反射机制来实现的(如:Spring MVCORM框架等),Java反射在编写漏洞利用代码、代码审计、绕过RASP方法限制等中起到了至关重要的作用。

参考文章

Java代码审计基础之反射 - FreeBuf网络安全行业门户

(4条消息) Java反射详解_潘建南的博客-CSDN博客

Java 反射由浅入深 | 进阶必备 (juejin.cn)

Java反射机制 · 攻击Java Web应用-[Java Web安全] (javasec.org)