Java反射详解及作用

参考视频链接: 哔哩哔哩视频.

1. 反射概述

能够分析类能力的程序叫做反射(reflective),对于任何一个Class类,反射可以在运行时直接得到这个类的全部成分,包括构造器,成员方法,成员变量。获得的构造器对象为Constructor,成员方法对象为Method,成员变量对象为Field。这种在运行时动态获取类信息以及动态调用类中成分的能力叫做Java语言的反射机制。
在这里插入图片描述

2. 获取编译后的Class类对象

反射的关键,或者说第一步,是获取编译后的Class类对象。

2.1 通过java.lang.Class类获取

对于Class类(java.lang.Class),定义了静态方法forName(String className)方法,获取Class类对象,className要写全限名,也就是包名+类名。假设我们在包com.reflective下创建了Student类,可以使用:

Class.forName("com.reflective.Student");

2.2 通过目标类获取

对于要反射的类,可以通过类名.class获得Class类对象。例如Student.class.

2.3 通过目标对象获取

在运行时,可以通过对象.getClass()获得对象所属类的Class类对象,这个是Object类的方法,因此所有类都有这个方法。例如student.getClass().
在这里插入图片描述

3. 反射获取构造器对象

在获得了Class类对象之后,通过调用Class类对象的方法可以获得其构造器对象Constructor。
在这里插入图片描述

3.1 获得Constructor对象

3.1.1 getConstructors()

获取Class类对象中的所有构造器对象,返回值为构造器数组,注意这个方法只能获取public修饰的构造器。

3.1.2 getDeclaredConstructors()

获取Class类对象中的所有构造器对象,返回值为构造器数组,即使是private修饰的构造器也能拿到!

3.1.3 getConstructor()

获取Class类对象中的一个构造器,实参应该依次传入该构造器形参的Class类对象。举个例子:

Class class = student.getClass();
class.getConstructor(String.class, Integer.class);

3.1.4 getDeclaredConstructor()

获取Class类对象中的一个构造器,实参应该依次传入该构造器形参的Class类对象,即使是private修饰的构造器也能拿到。
在这里插入图片描述

3.2 通过构造器初始化对象

获得构造器的作用是初始化一个对象返回。调用构造器的newInsrance方法,并且传入初始化参数(如果构造器需要的话),可以初始化对象并返回。需要注意的是如果是private修饰的构造器,即使获得了也不能直接newInstance,应该先调用构造器的setAccessible(true),才能初始化对象。
在这里插入图片描述

4. 反射获取成员变量对象

在获得了Class类对象后,可以调用Class类对象的方法获得成员变量,并对其赋值或者取值。

在这里插入图片描述

4.1 获得Field对象

4.1.1 getFields()

获取Class类对象的所有public成员变量对象的数组。

4.1.2 getDeclaredFields()

获取Class类对象的所有成员变量对象的数组,即使是private修饰的成员变量也能拿到。

4.1.3 getField()

获取Class类对象的单个public成员变量对象。传入参数为成员变量名字。

4.1.4 getDeclaredField()

获取Class类对象的单个成员变量对象,即使是private修饰的成员变量也能拿到。传入参数为成员变量名字。
在这里插入图片描述

4.2 取值赋值

获得了Field对象后,调用它的set()方法可以为属性赋值,第一个参数传入目标对象,如student,第二个参数传入值;调用get方法可以获得值,传入目标对象。
在这里插入图片描述

5. 反射获取方法对象

在这里插入图片描述

5.1 获得Method对象

5.1.1 getMethods()

调用Class类对象的getMethods()方法,能获得该类的所有public修饰的Method对象的数组。

5.1.2 getDeclaredMethods()

调用Class类对象的getDeclaredMethods()方法,能获得该类的所有Method对象的数组,即使是private修饰也可以获取。

5.1.3 getMethod()

调用Class类对象的getMethod()方法,能获得该类的指定的由public修饰的Method对象,传入第一个参数为方法名,后面的参数为方法形参的Class类,例如String.class。

5.1.4 getDeclaredMethod()

调用Class类对象的getDeclaredMethod()方法,能获得该类的指定的Method对象,传入第一个参数为方法名,后面的参数为方法形参的Class类,例如String.class。即使是private修饰也可以获取。
在这里插入图片描述

5.2 触发该方法执行

获得Method对象之后。调用它的invoke()方法可以触发该方法执行,传入第一个参数为已经实例化的对象,例如student,后面的参数为调用方法需要传递的参数。
如果想执行private修饰的方法,需要先调用Method对象的setAccessible(true)方法,再调用invoke()方法。
在这里插入图片描述

6. 反射的作用

6.1 绕过编译阶段为集合添加数据

集合中如果加了泛型,则只能在该集合中添加这种类型的数据,例如ArrayList,便只能添加Integer类型的数据。泛型只是在编译阶段可以约束集合只能操作某种数据类型,在java文件编译成class文件进入运行阶段的时候,其真实类型都是ArrayList,泛型相当于被擦除了。反射是作用在运行时的技术,因此可以绕过编译阶段为集合添加数据。例如:

ArrayList<Integer> list = new ArrayList<Integer>();
list.add(100);
list.add(200);
//会编译报错
//list.add("word");
Class c = list.getClass();
Method method = c.getDeclaredMethod("add",Object.class);
//list会添加word字符串,并且不会报错
method.invoke(list,"word");

6.2 通用框架的底层原理

使用反射能够实现图中的需求,这个需求其实是通用框架的底层原理。如接受到一个对象后,不清楚成员变量有几个,成员变量名是什么,等。这些都可以通过上面的反射机制来解决,因此通过反射可以完成这些需求。
在这里插入图片描述


版权声明:本文为qq_41523340原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>