反射(-)
反射作为 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)
第一个参数用于指定调用类,后面的变长参数是传给函数的参数。