什么是反射
反射就是把Java类中的各个成分映射成一个个的Java对象。
即在运行状态中,对于任意一个类,都能够知道这个类的所以属性和方法;对于任意一个对象,都能调用它的任意一个方法和属性。这种动态获取信息及动态调用对象方法的功能叫Java的反射机制。
优/缺点
优
1.可以在运行程序过程中,操作这些对象
2.可以降低耦合度,提高程序的可拓展性
缺
1.反射很强大,但是消耗性能,主要是为了做工具和框架使用的
反射机制的功能
Java反射机制主要提供了以下功能:
- 在运行时判断任意一个对象所属的类。
- 在运行时构造任意一个类的对象。
- 在运行时判断任意一个类所具有的成员变量和方法。
- 在运行时调用任意一个对象的方法。
- 生成动态代理。
实现反射机制的类
Java中主要由以下的类来实现Java反射机制(这些类都位于java.lang.reflect包中):
- Class类:代表一个类。 Field类:代表类的成员变量(成员变量也称为类的属性)。
- Method类:代表类的方法。
- Constructor类:代表类的构造方法。
- Array类:提供了动态创建数组,以及访问数组的元素的静态方法。
反射的基本原理
一说到基本原理,有些同学可能就会觉得有些头痛,坦率地说,如果真要从源头说起的话,可能需要从 JVM 的类加载机制与对象的创建过程说起,但这两点稍微展开一说,都需要很长的篇幅,而这不是本文的重点。所以,此处大家只需要知道有这样一个过程就好了,JVM 类加载、对象创建大概过程简化如下:(实际过程复杂的多,此处简化细节便于理解反射,以 User 对象为例)
1、将User.java
源码编译成User.class
二进制字节码文件;
-
2、JVM 将
User.class
二进制字节码文件加载到 JVM 内存中,并生成 User 对应的唯一的java.lang.Class
对象; (任意实际对象,JVM 类加载器加载时都会创建其对应的唯一的 1 个 Class 对象) -
3、当我们通过
User user = new User();
这种方式创建一个 User 对象时,JVM 就会通过 User 对象对应的java.lang.Class
对象来实例化一个 User 对象;(JVM 通过new
这个关键字,为我们“屏蔽”了类的加载检测、加载、初始化等过程,从而使我们实例化一个对象变得非常容易) -
4、反射,则是 JDK 为我们提供了几个基础核心类,让我们可以通过 API 的方式直接去加载 JVM 内存中相关类的 Class 对象,从而可以获取类的构造函数、方法、属性等,并实例化对象。(如果 JVM 内存中已经存在了实例化的对象,通过反射的方式,则可以修改该对象的属性和方法内容等)
JDK 中,关于反射相关操作的类、方法众多,笔者此处对其中核心的类、方法简单说明:
1、java.lang.Class
表示类的实体,在运行中的 Java 应用程序中表示类和接口。获取一个类的 Class 对象,通常有如下 3 种方式:
// 1、通过已存在的对象的getClass()方法获取 User user = new User(); Class clazz1 = user.getClass(); // 2、通过类的静态属性 class 获取 Class clazz2 = User.class; // 3、通过java.lang.Class类的静态方法 Class.forName(“全限定名”)获取 (最常用,即上文笔者用的方式) Class clazz3 = Class.forName("com.xiaojiang.demo.reflect.User");
当获取到 java.lang.Class
对象后,就可以通过相应 API 获取对象的构造函数、方法、属性、访问修饰符等信息,根据这些信息就可以实例化一个对象,并对其进行相关操作。
2、 java.lang.reflect.Constructor
表示类的构造函数(构造方法)
Constructor constructor = clazz.getConstructor();
3、java.lang.reflect.Method
表示类的方法。
Method method = clazz.getDeclaredMethod("doSomethingByName",String.class);
4、java.lang.reflect.Field
表示类的属性。
Field field = clazz.getDeclaredField("name");
5、java.lang.reflect.Modifier
用于判断类、方法、属性的访问修饰符,如private
、public
。
Modifier.isPublic(method.getModifiers());
通过反射方式创建对象、调用对象的方法、属性有了进一步的理解,此处简单说明如下:
反射的应用场景
以下列出几项利用了 Java 反射机制的应用场景:
-
动态代理实现;
-
自定义注解;
-
序列化与反序列化;
-
JDBC 实现;
-
Spring 的 IOC、AOP;
小结
1、Java 反射特性的存在,是 Java 语言被认为是半动态语言的重要原因之一。因为反射机制的存在,我们可以灵活地实现很多功能。
2、JDK 提供了一个功能丰富的反射库工具集(java.lang.reflect
包下),通过该工具集,我们可以方便地操作反射相关的功能。
3、反射的真正运用,远比本文示例中的复杂,如 Modifier 类,本文仅从基础的角度帮助理解大概流程。
4、如果需要深入理解反射机制,需要知道 JVM 类加载机制以及 Java 类的创建过程,有兴趣的可以去了解相关知识。
5、日常工作中,如果不是写底层框架相关代码的话,直接写反射代码的情况不会很多,但是几乎所有的 Java 技术栈相关的框架都有用到反射,所以,理解反射的基本原理,有利于我们理解整个 Java 技术栈相关技术的运行原理,可以说是刚需。
6、需要注意 Java 中对象和实例的区别,如:User 是一个用户对象,但不是实例,因为其只是一个抽象的概念,不表示某一个具体存在的实体,User 实例化的 xiaojiang 这个用户才是一个具体的实体。