如何理解反射?

在开发过程中我们会经常听到、见到、乃至使用到反射,但是对于反射的理解大家应该都有自己的独特见解,本文章仅在叙述个人对反射的理解,如有补充请评论。
在讲述个人理解之前,先来看一下Oracle官方对反射的解释:
如何理解反射?
看到英文应该就有人头疼了,不要紧,可以用百度翻译一下,大概的意思就是:反射使Java代码能够发现有关已加载类的字段、方法和构造函数的信息,并在安全限制内使用反射的字段、方法和构造函数对其底层对应项进行操作。API容纳需要访问目标对象的公共成员(基于其运行时类)或给定类声明的成员的应用程序。它还允许程序抑制默认的反射访问控制。
反射的核心就是JVM在运行时动态加载类或者调用方法/访问属性,而不需要在写代码或者编译期知道运行对象是谁。
Java反射框架主要提供的功能有:
1、在运行时判断任意一个对象所属的类
2、在运行时构造任意一个类的对象
3、在运行时判断任意一个类所具有的成员变量和方法-私有方法也可以
4、在运行时调用任意一个对象的方法
基于Class类的反射应用
A.Class是一个类,一个描述类的类(即描述类),封装了描述方法的Method,描述字段的Field,描述构造器的Constructor等属性
B.对象反射(照镜子)后可以得到的信息:某个类的数据成员名,方法和构造器以及某个类实现了那些接口
C.对于每个类而言,JRE都为其保留一个不变的Class类型的对象,一个Class对象包含了特定某个类的有关信息
D.Class对象只能由系统建立对象
E.一个类在JVM中只会有一个Class实例

总结:JDK中有一个类-Class,这个类封装了所有Java类型,包括这些类的所有信息,JVM中类信息放在方法区
那么根据上边的解释,我们就可以了解到,反射的过程其实是发生在程序的运行态,拿到编译阶段(类加载)过程中加载到JVM中的类信息,其实本质上反射就类似于是一个镜子,将java code和加载到JVM内存中的属性、方法以及类信息形成对照。

如何理解反射?
上边扯了很多的概念,估计都得头晕晕了,接下来就说一下反射的常见使用:
获取Class对象
这里的Class对象和声明类使用的class是不一样的点击这里了解
1.Class<?> clazz=Class.forName(“全限定类名”),返回的clazz其实是全限定类名的类的Class类对象引用,指向这个类以及类的字节码文件信息
2.Class<?> clazz=object.getClass() 通过引用得到Class对象
3.Class<?> clazz=Object.class 通过类字面量常量获得(懒加载)
获得构造器
获得构造器我们就需要借助jdk提供的reflect包下的constructor类
1.获得指定构造器
Constructor getConstructor(Class<?>…parameterTypes)
parameterTypes是Class[],里边的元素和元素顺序与构造器参数对应(本质上这种方式就是创建一个带参的类)
1.1Constructor constructor=getConstructor(new Class[]{}),获得默认构造器
1.2Constructor constructor=getConstructor(new Class[]{String.Class,int.Class}),获得参数为(String,int)的构造器
2.获得所有构造器
Constructor[] constructor=clazz.getConstructors()
获得字段
1.获得public字段
1.1Field field=clazz.getField(String name);获得对应名称的字段
1.2Filed[] fields=clazz.getField();获得所有public字段
2.获得自身字段(所有字段)
2.1Field field=clazz.getDeclareField(String name);获得当前类中定义的所有字段—tips:所有
2.2Field[] fields=clazz.getDeclareField();获取所有字段的数组
3.获得所有字段(include 父类字段)
3.1getSuperClass()获得父类Class对象,然后循环调用getSuperClass()和getDeclaredField[],将Field放入List中即可
获得方法
1.获得public方法
1.1Method method=clazz.getMethod(String name,Class<?>…parameterTypes);
name是方法名,parameterTypes是Class[],用来获取方法参数的类型
注意:这种方式只能够获取到当前引用类以及父类的public方法,其他权限无法获得
1.2Method[] methods=clazz.getMethods();获得所有方法
2.获得自身方法
2.1Method method=clazz.getDeclaredMethod(String name,Class<?>…parameterTypes);获得当前类定义的所有方法,不包括父类
2.2Method[] methods=clazz.getDeclaredMethods();获得所有方法
注意:这种方式虽然可以获得私有或者保护修饰符的方法,但是无法使用,需要有强制穿透才可以
3.获得所有方法(include 父类方法)
同获得所有字段的操作,不再赘述
创建实例对象
1.通过反射得到的构造器创建实例(推荐使用,可降低耦合度)
1.1无参构造器创建对象
XXX xxx=(XXX)constructor.newInstance();
1.2.带参构造器创建对象
XXX xxx=(XXX)constructor.newInstance(xx);
2.通过Class对象创建实例
XXX xxx=XXX.class.newInstance();
3.new、反序列化、clone()等方式
通过反射调用方法
1.method.invoke(Object obj,Object … args)传入实例对象obj和方法对应的参数
2.private修饰的方法无法反射(上边有提到),需要设置method.setAccessible(true)强制穿透才能够完成反射调用

本人才疏学浅,如有不准确的地方,评论区可以提出大家的见解,下边我也列举两篇博客供大家参考
参考1
参考2
同时也提出一个问题,大家可以思考一下:反射机制到底是不是安全的?如果是安全的为什么是安全的?

上一篇:Java基础-反射机制


下一篇:java.lang.reflect,反射,Java.lang.Class,注解 2021.1.6