1. 概述
- Java可称为“准动态语言”,有一定的动态性,可以利用反射机制获得类似动态语言(即在运行时代码可依据某些条件改变自身结构)的特性。
- 反射机制:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
- 要想解剖一个类,必须先要获取到该类的字节码文件对象。
- 反射相关的主要API
java.lang.Class: 代表一个类
java.lang.reflect.Method : 代表类的方法
java.lang.reflect.Field : 代表类的成员变量
java.lang.reflect.Constructor : 代表类的构造器
2. Class类
-
在Object类中定义了方法:public final Class getClass(),此方法将被所有子类继承。
-
(1)Class 本身也是一个类
(2)Class 对象只能由系统建立对象
(3)一个加载的类在 JVM 中只会有一个Class实例
(4)一个Class对象对应的是一个加载到JVM中的一个.class文件
(5)每个类的实例都会记得自己是由哪个 Class 实例所生成
(6)通过Class可以完整地得到一个类中的所有被加载的结构
(7) Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的 Class对象 -
Class类的常用方法
-
Java内存分析
3. 获取Class对象的三种方式
-
① Object类的getClass()方法
② 静态属性class
③ Class类中静态方法forName() -
案例:
-
运行结果:
4. 获取类的结构信息
- 对象就包含了完整的类的结构信息。可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,如类名、属性(字段)、方法、构造器等。
- 代码演示:
5. 创建类的对象
-
调用forName()返回的是Class,后需要调用newInstance()实例化
-
方式一: 调用Class对象的newInstance()方法,条件:①类必须有一个无参数的构造器, ②类的构造器的访问权限需要足。
-
方式二:1)通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的指定形参类型的构造器 2)向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。 3)通过Constructor实例化对象
-
代码:
-
运行结果:
6. 调用指定的方法
-
通过反射,调用类中的方法,通过Method类完成。
① 通过Class类的getMethod(String name,Class…parameterTypes)方法取得 一个Method对象,并设置此方法操作时所需要的参数类型。
② 之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传 递要设置的obj对象的参数信息。 -
代码:
-
若原方法声明为private,则需要在调用invoke()方法之前,显示调用方法对象的setAccessible(true)方法,将可访问private的方法。
-
代码:
7. 反射操作泛型
- Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题,但是一旦编译完成,所有和泛型有关的类型全部擦除。
- 为了通过反射操作这些类型 , Java新增了 ParameterizedType , GenericArrayType , TypeVariable 和 WildcardType 几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型。
- ParameterizedType : 表示一种参数化类型,比如Collection GenericArrayType : 表示一种元素类型是参数化类型或者类型变量的数组类型
TypeVariable : 是各种类型变量的公共父接口
WildcardType : 代表一种通配符类型表达式