Java安全-反射
Java安全可以从反序列化说起,而反序列化可以从反射说起。
Java反射机制:对于任意一个类都能知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意方法。这种动态获取信息以及动态调用方法的功能称为反射机制。
反射的作用:让Java具有动态性
正射与反射
正射
我们需要用到某个类的时候,都会先了解这个类是作什么的,然后实例化这个类,接着用实例化后的对象进行操作,这就是正射。
1 | Student st= new Student(); |
反射
而反射就是,一开始并不知道我们要初始化的对象是什么,自然也就无法使用new关键字来创建对象了
1 | Person p = new Person(); |
理解反射的第一步就是要搞清楚Class是什么
Java Class对象
Class类全称java.lang.Class类。
Java是面向对象的语言,讲究万物皆对象,即使再强大的一个类,依然是另一个类(Class类)的对象。也就是说,普通类是Class类的对象,Class类是所有类的类。
程序在运行的时候会编译生成一个.class文件,而这个.class为文件中的内容就是相对应类的所有信息。
比如
1 | public class abc { |
Class类的对象作用是运行时提供或获得某个对象的类型信息。
反射组成相关的类
反射机制相关操作一般位于java.lang.reflect包中
重点注意以下类:
- java.lang.class:类对象
- java.lang.reflect.Constructor:类的构造器对象
- java.lang.reflect.Field:类的属性对象
- java.lang.reflect.Method:类的方法对象
反射常用方法
- 获取类的方法:forName
- 实例化类对象的方法:newInstance
- 获取函数的方法:getMethod
- 执行函数的方法:invoke
class对象的获取方法
理解Java反射机制首先要理解Class类,而在反射中想要获取一个类或调用一个类的方法,首先需要获取到该类的Class对象
普通类采用以下方法
1 | Person person = new Person(); |
创建Class类时不能使用上述方法,会报错
跟进源码看看,发现构造器是私有的,只有JVM才能创建对象,所以无法通过创建对象的方式来获取class对象
一般获取class对象有以下三种方法:
- 实例化对象的getClass方法
存在某个类的实例,通过obj.getClass获取它的类
1 | Person p = new Person(); |
- 使用类的.class方法
1 | Person person = new Person(); |
- Class.forName(String className)动态加载类
1 | Class c1 = Class.forName("serialize.Person"); |
下面来看一个demo
1 | Class c1=Person.class; |
上面三种获取Class类的方式中,一般使用第三种通过Class.forName方式动态加载类,这种方式不需要再导入其他类,可以加载任意的类
使用类.class,需要导入类的包,依赖性太强
使用实例化对象的getClass方法,需要本身就创建一个对象,这样就失去了使用反射机制的意义
所以获取class对象,一般使用Class.forName方法获取
获取成员变量Field
获取成员变量Field位于java.lang.reflect.Field包中
- Field[] getFields():获取所有public修饰的成员变量
- Field[] getDeclaredFields():获取所有的成员变量,不包括修饰符
- Field getField(String name):获取指定名称的public修饰的成员变量
- Field getDeclaredField(String name):获取指定的成员变量
获取成员方法Method
- Method getMethod(String name,类<?>…parameterTypes):返回该类声明的public方法
- Method getDeclaredMethod(String name,类<?>…parameterTypes):返回该类声明的所有方法
第一个参数获取该方法的名字,第二个参数获取标识该方法的参数类型
- Method[] getMethods():获取所有public方法,包括类自身声明的public方法,父类public方法,实现的接口方法
- Method[] getDeclaredMethods():获取该类中所有方法
Person.java添加以下内容
1 | public void study(String s){ |
abc.java
1 | package serialize; |
获取构造函数Constructor
- Constructor<?>[] getConstructors():只返回public构造函数
- Constructor<?>[] getDeclaredConstructors():返回所有构造函数
- Constructor<> getConstructor(类<?>…parameterTypes):匹配和参数配型相符的public构造函数
- Constructor<> getDeclaredConstructor(类<?>…parameterTypes):匹配和参数配型相符的构造函数
Person.java
1 | private String name; |
abc.java
1 | package serialize; |
反射创建类对象
通过反射来生成实例对象,一般使用Class对象的newInstance()方法来创建类对象
1 | Class c =Class.forName("serialize.Person"); |
invoke方法,位于java.lang.reflect.Method类中,用于执行某个对象的目标方法,一般和getMethod方法配合使用
1 | public Object invoke(Object obj,Object... args) |
第一个参数为类的实例,第二个参数为相应函数中的参数
- obj:从中调用底层方法的对象,必须是实例化对象
- args:用于方法的调用,是一个object的数组,参数可能是多个
但是第一个参数不固定,如果调用的方法是普通方法,那么第一个参数就是类对象,如果是静态方法,那么第一个参数就是类
写个小demo
1 | package serialize; |
反射构造Runtime类执行
直接使用上面的demo会报错
这是因为Runtime类的构造方法是私有的
但是可以通过getRuntime来获取Runtime对象
1 | package serialize; |
也可以简化一下
1 | try{ |
小结
说白了反射也就是先获取类,并进行实例化对象,然后获取类里面的属性,调用类里面的方法。
- Title: Java安全-反射
- Author: p0l1st
- Created at : 2024-07-26 14:25:49
- Updated at : 2024-11-04 10:50:01
- Link: https://blog.p0l1st.top/2024/07/26/Java安全-反射/
- License: This work is licensed under CC BY-NC-SA 4.0.