本文的主要资料来源于《Thinking in Java》以及尚硅谷宋宏康老师的视频课程,附上视频链接:https://www.bilibili.com/video/BV1Kb411W75N,有兴趣的读者可以自行B站前往观看
1.反射的概念
反射是被视为动态语言的关键,反射机制允许程序在执行期间借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性和方法。反射就是在编译的时候将类的结构保存到方法区中,只有在运行时才动态地获取类的对象、属性、方法
2.为什么要使用反射
一般的,我们获取某个类的对象最常用的方式是使用new()
关键字,来创造一个具体的对象,而这个对象是在编译期间就已经创建好了的。那么为什么需要在运行期也创建对象呢,这里就涉及到另一个Java特性——泛型。
3.反射的运行原理
Java虚拟机在读取某个类的文件字节码(.class文件)的时候,会将这个类加载到JVM之中,并产生一个Class对象,而且只会产生一个,这个Class对象包含了该类的属性、方法、构造函数、包等各种信息,在运行时期间,外部可以通过某些手段动态地获取该类的这些信息,具体类的加载流程参见《深入理解Java虚拟机》。
图1 Java中正常创建对象和反射的流程
4.反射的使用
4.1获取Class类的三种方式
以Apple类为例
class Apple {
public String name;
public Integer type;
public Apple(){}
public Apple(String name, Integer type) {
this.name = name;
this.type = type;
}
}
在Test类中使Apple类
public static void main(String[] args) throws ClassNotFoundException {
/* 1.使用Class.forName方法 */
Class<?> clazz = Class.forName("com.kundi.loader.Apple");
/* 2.使用类的.class属性 */
Class<Apple> aClass = Apple.class;
/* 3.使用对象的.getClass方法 */
Apple apple = new Apple();
Class<? extends Apple> aClass1 = apple.getClass();
}
上面的<?>
属于泛型的范畴,看不懂的可以忽略,重点是Class类。不难看出,上面三种创建Class对象的三种方式中,第一种是相对方便,也是最常用的,因为可以根据参数字符串确定所要创建的Class对象;而第二中则需要提前知道类名,缺少灵活性;第三种就更不灵活了,都已经获取了对象了,再获取Class对象意义不大,除非是要调用某些访问修饰符为private或其他访问不到的类型。
4.2 Class类的使用
那么,拿到了Class类能够干什么用呢?是否真如想象中的那么灵活?关于反射类的包,均存在于JDK的java.lang.reflect
包下,里面的API也很多,但并不是每一样都能用得上,典型的用的比较多的有下面这些:
(1)通过反射创建类的对象
Apple apple1= (Apple)clazz.newInstance();
注意:这里要将Object类强转为Apple类,而且使用Class.newInstance()使用的是默认无参构造方法
(2)获取反射类的构造器
Constructor constructor = clazz.getConstructor(String.class, Integer.class);
Apple apple2 = (Apple) constructor.newInstance("红富士", 1);
这里可以获取有参的构造方法,然后创建对象
(3)获取反射类的方法
Method[] methods = clazz.getMethods();
for (Method method: methods) {
System.out.println(method.getName());
}
打印结果如下:
除了Object本身自带的方法之外,也打印了Apple类的方法
(4)获取反射类的属性
其实在JavaSE部分,反射类用的并不多,而在JavaEE方面特别是Spring框架中用的比较广泛。
参考文章
[1]Java反射介绍
[2]大白话说Java反射:入门、使用、原理