前言
相比于Java的代理,在实际项目中反射其实要更常用的多,所以学好反射不仅是能懂得框架设计的原理,更能在日常工作开发中提高编程能力
使用
要使用Java反射首先要得到的就是Java的Class对象,这很重要,使用反射无非就是要获取到对应的类的Class对象,因为只有先获取到Class对象,你才能获取到类的实例,静态方法,构造方法,非静态方法等。
那么如何获取Class对象呢?获取Class对象的方式又有哪几种?
获取Class对象的四种方式:
- (对象.getClass()), 通过对象实例获取Class对象,如下:
js
体验AI代码助手
代码解读
复制代码
Person person = new Person();
Class personClass = person.getClass()
这种一般没什么啥用,因为一般而言使用反射就是为了获取类的class对象再获取类的实例,方法,这种方式是在你都已经知道Person类的前提下了。
- 类.class: 通过类来获取Class对象,如下
js
体验AI代码助手
代码解读
复制代码
Class personClass = Person.class
这种跟上一种一样有些鸡肋,上一个的使用前提是已知对象,这一个的使用前提是已知类。
- 通过 Class.forName() 传入类的路径获取:
js
体验AI代码助手
代码解读
复制代码
Class testClass = Class.forName("com.xx.Test");
这种是最常用的,前提是知道类路径
- 通过类加载器xxxClassLoader.loadClass()获取
js
体验AI代码助手
代码解读
复制代码
Class testClass = ClassLoader.loadClass("com.xx.Test");
类加载器有四种,启动类加载器,扩展类加载器,应用类加载器,自定义加载器,这种方式的前提和上一种一样,都是要先知道类路径。
Class.forName()和ClassLoader 两种获取class对象方式的区别:
回顾下类加载时机的知识,我们知道虚拟机规范严格规定了有且只有 5 种情况必须立即对类进行初始化,其中一种就是使用反射对类进行调用时,具体的话就是使用Class.forName()获取class对象的反射调用方式会触发类初始化,因为Class.forName
在加载类的同时会执行该类的静态代码块,因此具有类似于静态初始化的效果。
类加载和类初始化是两个概念,按照顺序而言,一个类要经过三个阶段,类加载,类初始化,类实例化。 会触发类初始化的类加载时机只有5种情况,这5种情况称为主动引用,其他的称为被动引用。但这5种情况中并不包含类加载器加载类的情况,所以第一点区别就是:
- Class.forName()会触发类的初始化,而ClassLoader加载类只是单纯的加载类
- 其他的区别就是使用方式的区别了,Class.forName得指定类的全限定名,而ClassLoader加载类的方式更灵活
反射的一些操作
获取到Class对象之后我们可以通过Class对象拿到什么呢?假设我们已经通过上述四种方式之一获取到Class对象。
- 可以获取类的对象实例
js
体验AI代码助手
代码解读
复制代码
Class testClass = ClassLoader.loadClass("com.xx.Test");
Test testObject = (Test)testClass.newInstance();
- 可以获取类的所有定义的方法
js
体验AI代码助手
代码解读
复制代码
Class testClass = ClassLoader.loadClass("com.xx.Test");
Method[] methods = testClass.getDeclaredMethods();
甚至可以获取指定方法并调用,获取私有方法,获取构造方法
- 可以获得类的属性比如字段
js
体验AI代码助手
代码解读
复制代码
Class testClass = ClassLoader.loadClass("com.xx.Test");
Field field = testClass.getDeclaredField("name");
原理
提到反射我们老说Class对象,Class对象,那么Class对象到底是什么,与我们代码中定义的类和生成的实例又有什么关系?
我们都知道Java是编译型语言,先编译后运行,所以就会有编译期和运行期。
学过JVM类加载机制肯定知道Java类生命周期的第一个阶段就是加载,而在这个阶段虚拟机做的第三件事即是为这个类生成java.lang.Class对象,所以这个Class对象硬要有所指,那就是类生成的Class字节码文件!而类的加载是在运行期,所以我们说JAVA反射机制是在运行状态中。所以有些人觉得为什么Class对象那么神奇能获取到各种方法和属性,但其实本来就是Java代码中的类生成的class文件,所以能获取到类的各种信息。