前言
反射是Java中一种动态(运行时),通过反射可以在java动态运行时,对于任意一个类,对象可以通过反射获取到他的类,类可以通过反射拿到所有方法(包括私有),动态获取信息,以及动态调用对象的方法的功能称为java语言的反射机制。
反射的具体使用步骤
在调用Java
反射机制,主要步骤包括:
- 获取 目标类型的
Class
对象.
- 通过
Class
对象分别获取Constructor
类对象、Method
类对象 & Field
类对象.
- 通过
Constructor
类对象、Method
类对象 & Field
类对象分别获取类的构造函数、方法&属性的具体信息,并进行后续操作.
反射获取类的class对象
要想使用反射,我们首先需要获得代操作的类所对应的Clas对象。
1.常用的获取Class对象有四种方法:
1
| Class clz = Class.forName("java.lang.String");
|
1
| Class clz = String.class;
|
1 2
| String str = new String("Hello"); Class clz = str.getClass();
|
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)
|
2.获取所有的构造函数(包括:私有、受保护、默认、公有)
1 2 3 4
| conArray = clazz.getDeclaredConstructors(); for(Constructor c : conArray)
|
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"}});
|
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);
|
反射获取类的成员属性&赋值(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
| Class runtimeClass1 = Class.forName("java.lang.Runtime");
Constructor constructor = runtimeClass1.getDeclaredConstructor(); constructor.setAccessible(true);
Object runtimeInstance = constructor.newInstance();
Method runtimeMethod = runtimeClass1.getMethod("exec", String.class);
Process process = (Process) runtimeMethod.invoke(runtimeInstance, cmd);
InputStream in = process.getInputStream();
System.out.println(IOUtils.toString(in, "UTF-8"));
|
总结
Java反射机制是Java动态性中最为重要的体现,利用反射机制我们可以轻松的实现Java类的动态调用。Java的大部分框架都是采用了反射机制来实现的(如:Spring MVC
、ORM框架
等),Java反射在编写漏洞利用代码、代码审计、绕过RASP方法限制等中起到了至关重要的作用。
参考文章
Java代码审计基础之反射 - FreeBuf网络安全行业门户
(4条消息) Java反射详解_潘建南的博客-CSDN博客
Java 反射由浅入深 | 进阶必备 (juejin.cn)
Java反射机制 · 攻击Java Web应用-[Java Web安全] (javasec.org)