反射(-)
反射作为 Java 高级特性之一,在框架开发中使用很多。
Class
Class 类用于表示已被 JVM 加载的类型(为避免歧义,文中用 “Class 实例” 代指类型),它的实例是 Java 基础数据类型、已被 Java 加载的类和实例。枚举是特殊的类,注解是特殊的接口,数组的类型实际也是类。
获取 Class 对象
Class 类没有公共的构造方法,所有 Class 实例都是 JVM 的类加载器的 defineClass 方法构建的。我们可以通过以下方法获取已存在的 Class 实例。
Object#getClass 方法
Object#getClass 方法用于获取一个对象实例对应的 Class 实例,如果是一个父类引用指向子类实例,返回结果仍然是实际的子类对应的 Class 实例。
String name = "cncsl"; |
注意调用第二次调用输出语句时控制台的输出是 class [Ljava.lang.String;,与普通的 String 对象相比,多了 [L 和 ;。
.class 和 .TYPE
所有的类和基本数据类型都有 class 属性(严格意义上来说基本数据类型不是对象,不能用“属性”二字来描述),可在没有可用实例时直接通过类名或基本数据类型关键字获取 Class 实例。此外每个基本数据类包装类都有 TYPE 属性,可用于获取对应基本数据类型的 Class 实例。
System.out.println(String.class);//class java.lang.String |
注意上方基本数据类型关键字的 .class、包装类的 .class 和 .TYPE 的对应关系, int.class == Integer.TYPE 为真、int.class == Integer.class 为假。
Class#forName 方法
有两个不同类型重载的 Class#forName 方法,通常用于显式的类加载,并返回 Class 实例。
public static Class<?> forName(String className):根据className参数指定的全限定名找到并加载相关类型,如果找不到抛出ClassNotFoundException异常。public static Class<?> forName(String name, boolean initialize, ClassLoader loader):与另一重载类似,参数initializa指定是否立即初始化,loader指定类加载器。
public class Main { |
这两个函数底层都是调用私有、静态的本地方法 Class#forName0 实现类加载的。
Examining Class Modifiers and Types
Member
一个类声明由字段、方法和构造器共同构成,可以统称为类的成员,反射 API 提供了三个类分别表示这三种成员,Class 类提供了相关方法用于获取这些类的对象。利用反射进行编程的过程实际就是通过 Class 对象获取到想要的成员对象,然后通过成员对象提供的功能进行操作。
下方表中,“继承”指在当前类的父类(以及父类的父类)中定义的 public 修饰的变量,“私有”意为被 private 修饰的。
Field:常翻译为字段或成员变量,对应
java.lang.reflect.Field。Class 实例方法 列举变量 可获取继承变量 可获取私有变量 getDeclaredField()否 否 是 getField()否 是 否 getDeclaredFields()是 否 是 getFields()是 是 否 Method:常翻译为方法或成员函数,对应
java.lang.reflect.Method。Class 实例方法 列举函数 可获取继承函数 可获取私有函数 getDeclaredMethod()否 否 是 getMethod()否 是 否 getDeclaredMethods()是 否 是 getMethods()是 是 否 Constructor:常翻译为构造器或构造函数,对应
java.lang.reflect.Constructor。Class 实例方法 列举构造器 可获取私有构造器 getDeclaredConstructor()否 是 getConstructor()否 否 getDeclaredConstructors()是 是 getConstructors()是 否
Field
Field 对象实例封装了一个字段的名称、类型、修饰符和注解,可用于动态的访问和修改字段的值。常用方法有:
- 基本信息
String getName()Class<?> getType()Type getGenericType()
- 获取:参数 obj 指定具体的类
- 用于基本数据类型的
getXxx(Object obj) - 用于对象的
get(Object obj)
- 用于基本数据类型的
- 修改:参数 obj 指定具体的类
- 用于基本数据类型的
setXxx(Object obj, Xxx value) - 用于对象的
set(Object obj, Object value)
- 用于基本数据类型的
Method
Method 对象实例封装了一个函数的名称、返回值类型、形参列表、异常列表等,可用于动态的调用。常用方法有:
基本信息:
String getName()Class<?> getReturnType()Class<?>[] getParameterTypes()Class<?>[] getExceptionTypes()
调用:
Object invoke(Object obj, Object... args)第一个参数用于指定调用类,后面的变长参数是传给函数的参数。