反射在java反序列化中是常用到的一个东西
反射是什么
反射就是java代码在JVM虚拟机中运行时,对于任意一个类
可以动态获取他的class
对象、属性、方法相关的信息
举个栗子
正常情况下,我们在调用某一个类的方法,是先实例化一个类对象,然后对象.方法
使用,像这样
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Person { String name="菜鸡"; public void learn(){ System.out.println("我是"+name); } }
public class ReflectionLearn{ public static void main(String[] args) throws Exception { Person p = new Person(); p.learn(); } }
|
再利用反射调用,像这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Person { String name="菜鸡"; public void learn(){ System.out.println("我是"+name); } }
public class ReflectionLearn { public static void main(String[] args) throws Exception{ Class p = Class.forName("Person"); Person person = (Person) p.newInstance(); person.learn(); } }
|
我们可以看到,这个过程是先用forName
方法找到了一个名为Person的类
用,然后用类
实例化出来一个对象person
,再调用learn
方法。
反射中常用的方法
forName
:获得一个类
getMethod
:获得类方法
newInstance
:用类实例化出一个对象
invoke
:执行函数
这里就要对java中一个特殊的类做一下了解–Class
类
Class
用于表示JVM运行时类或接口的信息,比如获取类名、判断该类是否是一个接口或是普通类等。当一个类被虚拟机加载后会在内存中创建一个该类的Class
对象,反射就是在操作这个Class
forName方法


这个方法有两种用法,第一种就是只需要一个类名参数Class.forName("Person")
第二种当中是三个参数,第一个还是类名,第二个布尔类型,表示是否初始化,第三个参数表示类加载器,一般情况下第一种用法比较多。
newInstance方法
class.newInstance方法的作用个就是对该类进行实例化
假设现在有一个类如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Person { public String name="李四"; private int age=3; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; }
public void learn(){ System.out.println("我是:"+name); } public void age(){ System.out.println("我年龄:"+age); } }
|
现在这样去使用
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class ReflectionLearn { public static void main(String[] args) throws Exception{ Class<?> p = Class.forName("Person"); Person person = (Person) p.newInstance(); Field[] personfields = p.getDeclaredFields(); for (Field f:personfields){ System.out.println(f); } person.learn(); person.age(); } }
|
可以看到这里newInstance
是没有参数的,并且这个方法是无参的

运行之后我们得到李四
和3
这两个结果,也就是实例化调用的是无参构造方法,那如何调用有参的构造方法呢?就需要用到getConstructor
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class ReflectionLearn { public static void main(String[] args) throws Exception{ Class<?> p = Class.forName("Person"); Constructor<?> personconstructor = p.getConstructor(String.class,int.class); Person person = (Person) personconstructor.newInstance("张三",24); Field[] personfields = p.getDeclaredFields(); for (Field f:personfields){ System.out.println(f); } person.learn(); person.age(); } }
|
getField方法
这个方法可以获取Class
对象中的成员变量

可以看到有四个相似的方法,带s就是获取多个,带Declared就是不管成员变量是public或是private都可以获取到
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class ReflectionLearn { public static void main(String[] args) throws Exception{ Class<?> p = Class.forName("Person"); Constructor<?> personconstructor = p.getConstructor(String.class,int.class); Person person = (Person) personconstructor.newInstance("张三",24); Field[] personfields = p.getDeclaredFields(); for (Field f:personfields){ System.out.println(f); } } }
|
1 2
| public java.lang.String Person.name private int Person.age
|
这里获取到name和age两个变量,然后下一步试图操作他,上一步newInstance("张三",24)
实例化对象的时候name
的值是张三
,下面用set()
方法去修改name
的值为王五
,这里set需要两个参数,第一个是一个对象,第二个顾名思义就是要改变的变量的值
1 2 3 4 5 6 7 8 9 10 11
| public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, obj, modifiers); } } getFieldAccessor(obj).set(obj, value); }
|
需要思考的一个问题就是为什么传person
而不是p
?首先p
是通过Class.forName
获得的一个原型类,person
是通过p
实例化出来的一个对象,我们要修改的是对象的值,所以set()
传的参数是person
。
1 2
| Field personname=p.getField("name"); personname.set(person,"王五");
|
用同样的方法修改age变量的时候,发现报错了,是因为age是一个private类型,需要用getDeclaredField()
,然后需要设置setAccessible(true)
。

1 2 3 4 5
| Field personage = p.getDeclaredField("age"); personage.setAccessible(true); System.out.println(personage); personage.set(person,666); person.age();
|
getMethod方法
这部分跟getField
方法用法差不多,主要是调用成员方法的时候用到了invoke
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class ReflectionLearn { public static void main(String[] args) throws Exception{ Class<?> p = Class.forName("Person"); Constructor<?> personconstructor = p.getConstructor(String.class,int.class); Person person = (Person) personconstructor.newInstance("张三",24); Method[] personmethods = p.getMethods(); for (Method m : personmethods){ System.out.println(m); } Method personlearn=p.getMethod("learn"); System.out.println(personlearn); personlearn.invoke(person); } }
|