Class / Reflect 反射核心源码
概述
Java 反射机制的核心入口是 java.lang.Class 类。每个被 JVM 加载的类都有一个对应的 Class 实例,通过它可以获取类的构造器、方法、字段、注解等元信息,并在运行时动态调用。
java.lang.reflect 包下的 Method、Field、Constructor、Array、Proxy 等类构成了反射操作的能力层,而 sun.reflect.ReflectionFactory 则是 JVM 提供的反射工厂,串联起 native 实现与 Java 实现。
本文基于 OpenJDK 21 源码,从 Class 的类加载入口开始,逐层深入到方法调用、字段读写、构造器创建等反射核心路径,解析其中的关键设计思想。
本文基于 OpenJDK 21 源码分析,关键实现会对比 JDK 8 到 JDK 21 的版本差异。
1. Class.forName() 的类加载
Class.forName() 是 Java 反射中最常用的类加载入口。它不仅能加载类,还会触发类的初始化——即执行 <clinit> 静态初始化块。
1.1 方法签名与调用链路
// java.lang.Class
@CallerSensitive
public static Class<?> forName(String className) throws ClassNotFoundException {
// 调用者敏感的实现:获取调用者的 Class 以确定 ClassLoader
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, caller.getClassLoader(), caller);
}
@CallerSensitive
public static Class<?> forName(String name, boolean initialize, ClassLoader loader)
throws ClassNotFoundException {
Class<?> caller = null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
caller = Reflection.getCallerClass();
}
return forName0(name, initialize, loader, caller);
}forName(String) 默认 initialize=true,传入当前调用者的 ClassLoader。最终都委托给 forName0() native 方法:
// java.lang.Class
private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader, Class<?> caller)
throws ClassNotFoundException;1.2 HotSpot native 实现
// hotspot/share/classfile/systemDictionary.cpp 及 相关代码
// Java_java_lang_Class_forName0 的 JVM 入口
JVM_ENTRY(jclass, JVM_FindClassFromCaller(JNIEnv* env, const char* name,
jboolean init, jobject loader,
jclass caller)) {
// 1. 解析类名(将 '.' 替换为 '/')
TempNewSymbol h_name = SymbolTable::new_symbol(name, CHECK_NULL);
// 2. 使用指定的 ClassLoader 加载类
Klass* k = SystemDictionary::resolve_or_fail(h_name, loader, caller, CHECK_NULL);
// 3. 如果 initialize=true,执行类的初始化(即 <clinit>)
if (init) {
InstanceKlass::cast(k)->initialize(THREAD);
}
return (jclass) JNIHandles::make_local(env, k->java_mirror());
}1.3 forName() vs ClassLoader.loadClass() 的关键区别
| 特性 | Class.forName(name) | ClassLoader.loadClass(name) |
|---|---|---|
| 初始化 | 默认触发(initialize=true) | 不触发初始化 |
<clinit> 执行 | 会执行静态初始化块 | 不执行(除非后续首次主动使用) |
| 调用者 | 当前线程的调用者 ClassLoader | 指定 ClassLoader |
| 典型场景 | JDBC 驱动加载(需执行静态注册) | 延迟加载、IoC 容器 |
// JDBC 4.0 之前,显式注册驱动
Class.forName("com.mysql.jdbc.Driver");
// Driver 的静态初始化块中有 DriverManager.registerDriver(new Driver())
// ClassLoader.loadClass() 不会执行静态块
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class<?> clazz = cl.loadClass("com.mysql.jdbc.Driver");
// <clinit> 尚未执行!DriverManager 中不会有该驱动1.4 forName(name, initialize, loader) 控制初始化
// 不触发初始化(等同于 ClassLoader.loadClass() 的行为)
Class.forName("com.example.MyClass", false, classLoader);
// 触发初始化(默认行为)
Class.forName("com.example.MyClass", true, classLoader);底层机制:JVM 在初始化类时会加锁(Class初始化锁),防止多个线程同时初始化同一个类——这是 JVM 类加载的线程安全保证。
2. Class.newInstance() 的废弃
// java.lang.Class
@Deprecated(since="9")
public T newInstance() throws InstantiationException, IllegalAccessException {
if (System.getSecurityManager() != null) {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
}
// 调用无参构造器
Constructor<?> tmpConstructor = cachedConstructor;
if (tmpConstructor == null) {
// 获取无参构造器
tmpConstructor = getConstructor0(new Class<?>[0], Member.DECLARED);
cachedConstructor = tmpConstructor;
}
// 安全检查
Class<?> caller = Reflection.getCallerClass();
if (newInstanceCallerCache != caller && tmpConstructor.getAccessCheckCount() >= 0) {
// ... 访问权限检查
}
return tmpConstructor.newInstance(caller);
}2.1 废弃原因(JDK 9 源码注释说明)
JDK 9 标记 @Deprecated(since="9"),官方废弃原因可归结为:
- 绕过编译期构造器参数检查:任何异常都会包装为
InvocationTargetException,丢失精确的类型信息 - 只能调用无参构造器:无法传入参数
- 不处理构造器抛出的已检查异常:
newInstance()签名只抛出InstantiationException和IllegalAccessException,不处理构造器本身抛出的已检查异常 - 数组和基本类型会抛异常:
void.class、int.class等会直接抛InstantiationException
// 废弃的用法
MyClass obj = MyClass.class.newInstance(); // @Deprecated
// 推荐的替代用法
Constructor<MyClass> constructor = MyClass.class.getDeclaredConstructor();
MyClass obj = constructor.newInstance();
// 带参数的构造器
Constructor<MyClass> constructor = MyClass.class.getDeclaredConstructor(String.class, int.class);
MyClass obj = constructor.newInstance("hello", 42);2.2 cachedConstructor 缓存优化
注意源码中使用了 cachedConstructor 字段缓存无参构造器:
// java.lang.Class
private transient Constructor<?> cachedConstructor;这意味着多次调用同一类的 newInstance() 不会重复反射查找,首次找到的无参构造器会被缓存,后续直接使用。这是 Class 内部一个小的性能优化。
3. Class.getMethod() 的 ReflectionData 缓存
反射获取方法/字段的开销很大,JDK 使用 ReflectionData 软引用缓存来优化这一过程。
3.1 ReflectionData 内部结构
// java.lang.Class
private static class ReflectionData<T> {
volatile Field[] declaredFields; // 所有声明的字段
volatile Field[] publicFields; // 公有字段
volatile Method[] declaredMethods; // 所有声明的方法
volatile Method[] publicMethods; // 公有方法
volatile Constructor<T>[] declaredConstructors; // 所有声明的构造器
volatile Constructor<T>[] publicConstructors; // 公有构造器
// 两级过滤缓存
volatile Field[] declaredPublicFields; // 声明为 public 的字段
volatile Method[] declaredPublicMethods; // 声明为 public 的方法
// 接口方法缓存
volatile Map<Class<?>, Method[]> declaredMethods...;
final Class<?> definingClass;
ReflectionData(Class<?> definingClass) {
this.definingClass = definingClass;
}
}3.2 软引用缓存机制
// java.lang.Class
private volatile transient SoftReference<ReflectionData<T>> reflectionData;
// 惰性初始化方法
private ReflectionData<T> reflectionData() {
SoftReference<ReflectionData<T>> reflectionData = this.reflectionData;
int c = this.classReflectionData; // 用于检测 GC 回收
if (useCaches &&
reflectionData != null &&
c != 0) {
// 软引用还存在,且未被 GC 回收
ReflectionData<T> data = reflectionData.get();
if (data != null) {
return data;
}
}
// 新建 ReflectionData(慢路径)
return newReflectionData(reflectionData, c);
}软引用(SoftReference):JVM 在内存充足时不会回收,但内存不足时(OOM 前)会回收。这保证了反射元数据在多数情况下被缓存,但在内存紧张时可以释放。
3.3 三级缓存读写逻辑
以 getMethod() 为例,调用链如下:
// java.lang.Class
public Method getMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
// 安全检查
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
// 获取方法(有缓存)
Method method = getMethod0(name, parameterTypes, true);
if (method == null) {
throw new NoSuchMethodException(methodToString(name, parameterTypes));
}
return method;
}其核心查询逻辑在 privateGetDeclaredMethods(boolean publicOnly):
// java.lang.Class
private Method[] privateGetDeclaredMethods(boolean publicOnly) {
checkInitted();
// 1. 尝试从缓存中读取
Method[] res;
ReflectionData<T> rd = reflectionData();
if (rd != null) {
if (publicOnly) {
res = rd.declaredPublicMethods; // 只获取 public 方法
} else {
res = rd.declaredMethods; // 获取所有声明的方法
}
if (res != null) return res;
}
// 2. 缓存未命中,调用 native 方法查询
res = getDeclaredMethods0(publicOnly);
// 3. 写入缓存
if (rd != null) {
if (publicOnly) {
rd.declaredPublicMethods = res;
} else {
rd.declaredMethods = res;
}
}
return res;
}三级缓存层次:
publicOnly=false → declaredMethods(所有方法,包括 private)
publicOnly=true → declaredPublicMethods(声明为 public 的方法)
↓
publicMethods(从 declaredPublicMethods 过滤继承来的 public 方法)3.4 GC 回收后重建
当内存不足时,SoftReference 引用的 ReflectionData 被回收。下次 reflectionData() 调用检测到 c == 0,会通过 newReflectionData() 新建:
// java.lang.Class
private synchronized ReflectionData<T> newReflectionData(
SoftReference<ReflectionData<T>> oldReflectionData, int classReflectionData) {
// 使用同步保证只有一个线程重建
ReflectionData<T> rd = new ReflectionData<>(this);
this.reflectionData = new SoftReference<>(rd);
this.classReflectionData = GENERATED_REFLECTION_DATA_ACCESSOR; // 标记
return rd;
}设计要点:
volatile保证多线程可见性,synchronized保证重建操作的线程安全,SoftReference提供 GC 友好的缓存淘汰策略。
4. Method.invoke() 的委派实现
Method.invoke() 是反射调用方法的核心入口。其底层并非直接调用 native,而是通过一个委派链来实现性能优化。
4.1 委派链总览
Method.invoke(obj, args)
→ DelegatingMethodAccessorImpl.invoke(obj, args)
→ NativeMethodAccessorImpl.invoke(obj, args) ← 前 15 次调用
→ GeneratedMethodAccessorXXX.invoke(obj, args) ← 15 次后切换4.2 Method.invoke() 入口
// java.lang.reflect.Method
@CallerSensitive
@ForceInline
public Object invoke(Object obj, Object... args) throws ... {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, declaringClass, ...);
}
// 委托给 MethodAccessor
return methodAccessor.invoke(obj, args);
}4.3 DelegatingMethodAccessorImpl 委托模式
// sun.reflect.DelegatingMethodAccessorImpl
class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
private MethodAccessorImpl delegate;
public Object invoke(Object obj, Object[] args) throws ... {
// 委托给被代理的 MethodAccessor(开始是 Native,之后换成 Generated)
return delegate.invoke(obj, args);
}
void setDelegate(MethodAccessorImpl delegate) {
this.delegate = delegate;
}
}DelegatingMethodAccessorImpl 本身只是一个中间层,它的核心意义在于允许运行时切换底层实现——从 native 切换到字节码实现,调用方(Method.invoke())完全感知不到这一变化。
4.4 NativeMethodAccessorImpl 的 native 调用
// sun.reflect.NativeMethodAccessorImpl
class NativeMethodAccessorImpl extends MethodAccessorImpl {
private final Method method;
private DelegatingMethodAccessorImpl parent;
private int numInvocations; // 调用计数
public Object invoke(Object obj, Object[] args) throws ... {
// 检测是否达到膨胀阈值
if (++numInvocations > ReflectionFactory.inflationThreshold()
&& !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
// 超过阈值:生成 Java 字节码实现
MethodAccessorImpl generated = (MethodAccessorImpl)
generatedMethodAccessor(method);
// 将 DelegatingMethodAccessorImpl 的委托切换为生成实现
parent.setDelegate(generated + generated);
}
// 本次仍走 native 调用
return invoke0(method, obj, args);
}
// native 方法:JNI 调用
private static native Object invoke0(Method method, Object obj, Object[] args);
}5. NativeMethodAccessorImpl 膨胀阈值
5.1 默认阈值 15
// sun.reflect.ReflectionFactory
private static int inflationThreshold = 15; // 默认值
public static int inflationThreshold() {
return inflationThreshold;
}可通过 JVM 参数配置:-Dsun.reflect.inflationThreshold=500
5.2 膨胀机制详解
调用次数 ≤ inflationThreshold:
NativeMethodAccessorImpl.invoke() → invoke0() native
特点:native 启动快(无需生成字节码),但每次调用有 JNI 边界开销
调用次数 > inflationThreshold:
DelegatingMethodAccessorImpl 的 delegate 被切换为 GeneratedMethodAccessorXXX
特点:生成字节码有初始开销(类加载、验证),但后续 JIT 可以内联优化5.3 设计意图
| 阶段 | 实现方式 | 优点 | 缺点 |
|---|---|---|---|
| 前 15 次 | Native (JNI) | 启动快,首次调用延迟低 | JNI 边界开销,无法 JIT 内联 |
| 15 次后 | Java 字节码 | JIT 可内联,消除反射调用开销 | 首次生成字节码有类加载开销 |
为什么是 15? 这是一个经验值——HotSpot JIT 编译通常在方法调用 10,000 次左右触发 C2 编译。反射方法调用次数少时,native 实现的启动延迟更低;调用次数多时,生成字节码让 JIT 接管更高效。15 次是在 HotSpot 团队实测中得出的较优经验值。
5.4 生成字节码示例
GeneratedMethodAccessor1 大致生成的字节码等价于:
// 假设原始方法为:public String Foo.sayHello(String name)
// 生成的字节码等价于:
public class GeneratedMethodAccessor1 extends MethodAccessorImpl {
public Object invoke(Object obj, Object[] args) {
// 直接转型并调用,无反射开销
Foo target = (Foo) obj;
String name = (String) args[0];
return target.sayHello(name); // 直接调用!JIT 可内联
}
}6. AccessibleObject.setAccessible() 的模块化检查
JDK 9 引入模块系统(JPMS)后,setAccessible() 的行为发生了根本性的变化。
6.1 JDK 8 及之前的行为
// 在 JDK 8 及之前,只要 SecurityManager 允许,就可以访问任意私有成员
Field f = String.class.getDeclaredField("value");
f.setAccessible(true); // 直接可用
Object value = f.get("hello");6.2 JDK 9+ 的模块化检查
// java.lang.reflect.AccessibleObject
public void setAccessible(boolean flag) throws SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
// JDK 9+ 增加模块化访问检查
this.override = flag;
}
// 实际检查在每次 invoke()/get()/set() 时通过 checkAccess() 进行当调用 setAccessible(true) 后,实际访问时(如 Method.invoke() 或 Field.get()),会调用 checkAccess():
// java.lang.reflect.AccessibleObject
static void checkAccess(Class<?> caller, Class<?> declaringClass, ...) {
// 模块化检查
if (caller.getModule() != declaringClass.getModule()) {
// 检查模块之间是否允许访问
if (!declaringClass.getModule().canAccess(caller.getModule())) {
throw new InaccessibleObjectException(
"Unable to make field " + ... + " accessible: " +
"module " + declaringClass.getModule().getName() +
" does not 'opens' " + declaringClass.getPackageName() +
" to " + caller.getModule().getName());
}
}
// ... 传统安全策略检查
}6.3 模块开放的三种方式
| 方式 | 命令/注解 | 作用范围 |
|---|---|---|
| 启动参数开放 | --add-opens java.base/java.lang=ALL-UNNAMED | 对整个模块开放包 |
| module-info.java | opens com.example.internal to other.module; | 编译期声明 |
| module-info.java | exports com.example.api; | 仅导出(export)不够,需 opens 才允许反射 |
// 示例:在 JDK 17+ 反射访问 String.value
Field f = String.class.getDeclaredField("value");
f.setAccessible(true);
// 如果未加 --add-opens,会抛出:
// java.lang.reflect.InaccessibleObjectException:
// Unable to make field private final byte[] java.lang.String.value accessible:
// module java.base does not 'opens java.lang' to unnamed module6.4 JDK 8 vs JDK 9+ 行为对比
| 场景 | JDK 8 | JDK 9+ |
|---|---|---|
| 访问非 public 字段 | 可直接 setAccessible(true) | 需模块开放,否则抛 InaccessibleObjectException |
| 访问 JDK 内部类 | 可通过 setAccessible(true) 绕过 | 默认禁止,需 --add-opens |
| SecurityManager | 默认不启用 | 默认不启用,模块检查是主要限制 |
| Hibernate/Spring 等 | 可直接反射访问私有字段 | 需模块开放,且 JDK 17+ 对 java.lang.reflect.Proxy 有额外限制 |
7. Field.getInt() / setInt() 的 FieldAccessor
字段读写通过 FieldAccessor 委派给 Unsafe 实现直接内存操作。
7.1 委派结构
Field.getInt(obj)
→ FieldDelegate.getInt(obj)
→ FieldAccessor.getInt(obj)
→ Unsafe.getInt(obj, offset) ← 直接内存读取7.2 Field 源码
// java.lang.reflect.Field
public int getInt(Object obj) throws IllegalArgumentException, IllegalAccessException {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, this.clazz, obj);
}
// 委托给 FieldAccessor
return getFieldAccessor(obj).getInt(obj);
}getFieldAccessor(obj) 根据字段类型创建对应的 FieldAccessor 实现。
7.3 Unsafe.fieldOffset() 获取字段偏移量
// sun.reflect.UnsafeFieldAccessorImpl
class UnsafeFieldAccessorImpl extends FieldAccessorImpl {
protected static final Unsafe unsafe = Unsafe.getUnsafe();
protected final Field field;
protected final int fieldOffset; // 字段在对象内存中的偏移量
protected final boolean isFinal;
UnsafeFieldAccessorImpl(Field field) {
this.field = field;
// 关键:获取字段在对象中的内存偏移
this.fieldOffset = unsafe.fieldOffset(field);
}
}Unsafe.objectFieldOffset() 返回字段相对于对象起始地址的字节偏移:
// hotspot/share/prims/unsafe.cpp
UNSAFE_ENTRY(jlong, Unsafe_ObjectFieldOffset(JNIEnv* env, jobject unsafe, jobject field)) {
// 获取字段在类布局中的偏移量
int offset = InstanceKlass::cast(k)->field_offset(fieldDescriptor->index());
return (jlong) offset;
}7.4 Unsafe.getInt() 与 putInt() 直接内存操作
// sun.reflect.UnsafeIntegerFieldAccessorImpl
class UnsafeIntegerFieldAccessorImpl extends UnsafeFieldAccessorImpl {
public int getInt(Object obj) throws IllegalArgumentException {
ensureObj(obj); // 类型安全检查
// 直接从内存读取 int 值
return unsafe.getInt(obj, fieldOffset);
}
public void setInt(Object obj, int v) throws ... {
ensureObj(obj);
if (isFinal) {
throw new IllegalAccessException("Field is final");
}
// 直接写入内存
unsafe.putInt(obj, fieldOffset, v);
}
public Object get(Object obj) throws ... {
return Integer.valueOf(getInt(obj));
}
}对应的 Unsafe 方法(HotSpot 实现):
// Unsafe.getInt(Object, long offset)
UNSAFE_ENTRY(jint, Unsafe_GetInt(JNIEnv* env, jobject unsafe, jobject obj, jlong offset)) {
oop p = JNIHandles::resolve(obj);
// 通过对象指针 + 偏移量,直接读取内存
jint x = *(jint*)(index_oop_from_field_offset_long(p, offset));
return x;
}
UNSAFE_ENTRY(void, Unsafe_PutInt(JNIEnv* env, jobject unsafe, jobject obj, jlong offset, jint x)) {
oop p = JNIHandles::resolve(obj);
// 通过对象指针 + 偏移量,直接写入内存
*(jint*)(index_oop_from_field_offset_long(p, offset)) = x;
}7.5 内存偏移示意图
对象内存布局:
┌─────────────────────────────────────────────┐
│ 对象头 (Mark Word + Klass Pointer) │ ← 偏移 0
├─────────────────────────────────────────────┤
│ int x ← 偏移 12 (示例) │ ← unsafe.getInt(obj, 12)
├─────────────────────────────────────────────┤
│ String s ← 偏移 16 (引用类型) │
├─────────────────────────────────────────────┤
│ long y ← 偏移 24 (对齐后的偏移) │
└─────────────────────────────────────────────┘性能优势:
Unsafe.getInt(obj, offset)就是一条 CPU 内存读取指令,零 JNI 开销(方法本身是@HotSpotIntrinsicCandidate,可以被 JIT 内联为 CPU 指令)。
7.6 Field.setXxx() 修改 final 字段的限制
UnsafeIntegerFieldAccessorImpl.setInt(obj, v) {
if (isFinal) {
throw new IllegalAccessException("Field is final");
}
unsafe.putInt(obj, fieldOffset, v);
}即使调用了 setAccessible(true),Field.set() 仍会检查字段是否为 final。要绕过此限制,需直接使用 Unsafe.putInt() 或 Unsafe.putObject()。
8. ReflectionFactory.newConstructorForSerialization()
这是 Java 序列化框架(ObjectInputStream 等)的核心 API,用于绕过构造器创建对象。
8.1 方法签名与语义
// sun.reflect.ReflectionFactory
public Constructor<?> newConstructorForSerialization(Class<?> clazz) {
// 返回一个"哑"Constructor,调用它不会执行类的构造器
// 而是直接通过 Unsafe.allocateInstance() 分配内存
return newConstructorForSerialization(clazz, Object.class.getDeclaredConstructor());
}
public Constructor<?> newConstructorForSerialization(Class<?> clazz,
Constructor<?> constructorToCall) {
// 确保 clazz 可序列化
if (!Serializable.class.isAssignableFrom(clazz)) {
return constructorToCall; // 非序列化类,返回原始构造器
}
// 创建一个新的 Constructor,其 newInstance() 调用的是 constructorToCall
// 而不是 clazz 的构造器
return generateConstructor(clazz, constructorToCall);
}8.2 与 Unsafe.allocateInstance() 的关系
Unsafe.allocateInstance(Class) 是更底层的 API,直接分配对象内存而不调用任何构造器:
// sun.misc.Unsafe
// 分配一个对象实例,但不执行任何构造器
public native Object allocateInstance(Class<?> cls) throws InstantiationException;
// 使用示例
Unsafe unsafe = Unsafe.getUnsafe();
MyClass obj = (MyClass) unsafe.allocateInstance(MyClass.class);
// obj 的所有字段为默认值(null, 0, false)ReflectionFactory.newConstructorForSerialization() 返回的 Constructor 内部最终也是调用 Unsafe.allocateInstance():
// sun.reflect.ReflectionFactory
Constructor<?> generateConstructor(Class<?> clazz, Constructor<?> constructorToCall) {
// 内部创建 SerializationConstructorAccessorImpl
// 其 newInstance() 实现为:
// Object obj = unsafe.allocateInstance(clazz); // 分配内存(不调用构造器)
// constructorToCall.newInstance(obj); // 手动调用父类构造器
// return obj;
}8.3 Java 序列化中的应用
// java.io.ObjectInputStream 的反序列化核心路径
public class ObjectInputStream {
private Object readOrdinaryObject(boolean unshared) throws IOException {
Object obj;
try {
// 核心:通过反射工厂获取序列化构造器
Constructor<?> cons = serializationConstructor(objCl);
// 调用构造器创建对象(但不执行该类的构造器)
obj = cons.newInstance();
} catch (...) { ... }
// 对于实现了 Serializable 的类:
// - 不调用该类的任何构造器
// - 对象通过 Unsafe.allocateInstance() 创建
// - 字段值通过反射直接写入
// 对于实现了 Externalizable 的类:
// - 调用 public 无参构造器
// - 然后调用 writeExternal() / readExternal()
}
// 获取序列化构造器
private Constructor<?> serializationConstructor(Class<?> cl) {
// 查找序列化构造器(无参构造器或符合序列化约定的构造器)
// 使用 ReflectionFactory.newConstructorForSerialization()
}
}8.4 典型序列化过程
ObjectInputStream.readObject()
│
▼
查找该类的序列化构造器
│
├── 如果 implements Serializable
│ → ReflectionFactory.newConstructorForSerialization(clazz)
│ → Unsafe.allocateInstance(clazz) ← 不调用任何构造器
│
├── 如果 extends Externalizable
│ → clazz.getConstructor() ← 调用 public 无参构造器
│
└── 否则
→ clazz.getDeclaredConstructor() ← 调用构造器(普通反序列化)
│
▼
通过反射设置字段值(ObjectStreamClass 中缓存的字段描述)
→ Field.set(obj, value)
→ Unsafe.putObject(obj, offset, value)8.5 实际应用场景
// 场景 1:单例模式被序列化破坏(无需额外防御时)
public class Singleton implements Serializable {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
}
// 反序列化后:不同的对象!因为构造器未被调用
// 场景 2:使用 readResolve() 防御
public class Singleton implements Serializable {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
private Object readResolve() { return INSTANCE; } // 替换反序列化结果
}
// 场景 3:框架中使用(如 Hibernate 的懒加载代理)
// Hibernate 使用 Unsafe.allocateInstance() 创建代理对象
// 绕过构造器来创建未初始化的代理实例9. 额外覆盖内容
9.1 Class 的 Type 泛型体系
Class 实现了 Type 接口,而 java.lang.reflect 下有完整的泛型类型体系:
// java.lang.reflect
public interface Type {
default String getTypeName() {
return toString();
}
}
public interface ParameterizedType extends Type {
Type[] getActualTypeArguments(); // 实际类型参数,如 List<String> → [String.class]
Type getRawType(); // 原始类型,如 List<String> → List.class
Type getOwnerType(); // 拥有者类型
}
public interface TypeVariable<D extends GenericDeclaration> extends Type {
Type[] getBounds(); // 上界,如 T extends Number → [Number.class]
D getGenericDeclaration(); // 声明该类型变量的 GenericDeclaration
String getName(); // 类型变量名,如 "T"
}
public interface WildcardType extends Type {
Type[] getUpperBounds(); // 上界,如 ? extends Number → [Number.class]
Type[] getLowerBounds(); // 下界,如 ? super Integer → [Integer.class]
}// 使用示例
public class Box<T extends Number> {
private T item;
private List<String> names;
}
// 获取字段的泛型类型
Field itemField = Box.class.getDeclaredField("item");
Type genericType = itemField.getGenericType(); // 返回 TypeVariable
System.out.println(genericType); // "T"
System.out.println(((TypeVariable<?>) genericType).getBounds()[0]); // "class java.lang.Number"
Field namesField = Box.class.getDeclaredField("names");
Type genericType2 = namesField.getGenericType(); // 返回 ParameterizedType
System.out.println(genericType2); // "java.util.List<java.lang.String>"
ParameterizedType pt = (ParameterizedType) genericType2;
System.out.println(pt.getActualTypeArguments()[0]); // "class java.lang.String"9.2 Array.newInstance() 反射创建数组
// java.lang.reflect.Array
public static Object newInstance(Class<?> componentType, int length)
throws NegativeArraySizeException {
return newArray(componentType, length);
}
// 创建多维数组
public static Object newInstance(Class<?> componentType, int... dimensions)
throws IllegalArgumentException, NegativeArraySizeException {
return multiNewArray(componentType, dimensions);
}Native 实现(HotSpot):
// hotspot/share/prims/unsafe.cpp (通过 JVM 入口)
JVM_ENTRY(void, JVM_NewArray(JNIEnv* env, jclass arrayClass, ...)) {
// 根据组件类型分配数组
oop arr = oopFactory::new_array(
typeArrayKlass::cast(ak), length, CHECK_NULL);
return JNIHandles::make_local(env, arr);
}// 使用示例
// 创建 int[10]
int[] arr = (int[]) Array.newInstance(int.class, 10);
Array.setInt(arr, 0, 42);
System.out.println(Array.getInt(arr, 0)); // 42
// 创建 String[3][4](二维数组)
String[][] matrix = (String[][]) Array.newInstance(String.class, 3, 4);
Array.set(matrix, 0, new String[] {"a", "b", "c", "d"});9.3 MethodHandle 与 VarHandle 对比
JDK 7 引入 java.lang.invoke 包,提供了比反射更高效的动态调用方案:
| 特性 | java.lang.reflect | java.lang.invoke.MethodHandle | VarHandle |
|---|---|---|---|
| 引入版本 | JDK 1.1 | JDK 7 | JDK 9 |
| 核心操作 | Method.invoke() | MethodHandle.invokeExact() | VarHandle.get() / set() |
| 类型检查 | 运行时(参数数组) | 编译期(签名多态) | 编译期(签名多态) |
| JIT 内联 | 膨胀后(15次后生成字节码) | 直接可内联 | 直接可内联 |
| 性能 | 慢(需装箱+数组+反射检查) | 接近直接调用 | 接近直接字段访问 |
| 安全性 | setAccessible 可绕过访问控制 | 受 Lookup 的查找上下文限制 | 受 Lookup 限制 |
| 字段操作 | Field.get/set (通过 FieldAccessor) | MethodHandle 的 Getter/Setter | 原生支持原子操作 |
| 原子操作 | 不支持 | 不支持 | 支持 compareAndSet、getAndUpdate 等 |
// MethodHandle 示例
public class MethodHandleExample {
public String greet(String name) {
return "Hello, " + name;
}
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findVirtual(
MethodHandleExample.class, "greet",
MethodType.methodType(String.class, String.class));
MethodHandleExample obj = new MethodHandleExample();
String result = (String) mh.invokeExact(obj, "World");
System.out.println(result); // "Hello, World"
}
}
// VarHandle 示例
public class VarHandleExample {
private int count = 0;
private static final VarHandle COUNT_HANDLE;
static {
try {
COUNT_HANDLE = MethodHandles.lookup()
.findVarHandle(VarHandleExample.class, "count", int.class);
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
public void increment() {
COUNT_HANDLE.getAndAdd(this, 1); // 原子自增,替代 synchronized
}
}9.4 Class.isAssignableFrom() vs instanceof
两者都用于判断类型兼容性,但有本质区别:
class Animal {}
class Dog extends Animal {}
public class TypeCheckExample {
public static void main(String[] args) {
Dog dog = new Dog();
// instanceof:需要左侧实例,编译期类型匹配
boolean b1 = dog instanceof Animal; // true
boolean b2 = dog instanceof Dog; // true
// boolean b3 = "string" instanceof Dog; // 编译错误!
// isAssignableFrom:运行时类型检查,无需实例
boolean b3 = Animal.class.isAssignableFrom(Dog.class); // true
boolean b4 = Dog.class.isAssignableFrom(Animal.class); // false
boolean b5 = Animal.class.isAssignableFrom(Animal.class); // true
// isAssignableFrom 适用于泛型场景
Class<?> clazz = getSomeClass();
if (Serializable.class.isAssignableFrom(clazz)) {
// 检查 clazz 是否实现了 Serializable
}
}
}| 特性 | instanceof | isAssignableFrom() |
|---|---|---|
| 操作数 | 左:对象实例,右:类名 | 左:Class 对象,右:Class 对象 |
| 使用场景 | 已有对象实例 | 只有 Class 元数据(如泛型、框架代码) |
| 编译期检查 | 是(不兼容类型会编译报错) | 否(全运行时) |
| null 安全 | null instanceof X → false | 参数为 null → false |
| 接口检查 | 支持 | 支持 |
| 数组 | 支持 | 支持 |
| 性能 | 字节码指令(较优) | 方法调用(稍慢) |
// 典型应用场景
// 场景 1:框架中判断类型兼容性
public <T> T createBean(Class<T> requiredType) {
for (Object bean : beanFactory.getBeans()) {
if (requiredType.isAssignableFrom(bean.getClass())) {
return (T) bean;
}
}
return null;
}
// 场景 2:运行时不确定类的情况下
Class<?> loadedClass = Class.forName("com.example.Dog");
if (Animal.class.isAssignableFrom(loadedClass)) {
Object animal = loadedClass.getConstructor().newInstance();
}10. 关键类结构一览
java.lang.Class<T> ← 反射入口
├── forName(String, boolean, ClassLoader) ← 类加载 + 初始化(native forName0)
│ └── (deprecated) newInstance() ← JDK 9+ @Deprecated
│ └── cachedConstructor ← 无参构造器缓存
├── getMethod() / getField() / getConstructor()
│ └── reflectionData() ← SoftReference<ReflectionData> 软引用缓存
│ ├── declaredMethods / declaredFields ← 所有声明的方法/字段
│ ├── publicMethods / publicFields ← 公有方法/字段
│ └── declaredPublicMethods/Fields ← 声明为 public 的方法/字段
├── getGenericType() ← 泛型类型信息
├── isAssignableFrom(Class) ← 运行时类型检查
├── getModule() ← JDK 9+ 模块信息
└── cast(Object) ← 类型安全转换
java.lang.reflect.Method ← 方法反射
└── invoke(obj, args)
└── DelegatingMethodAccessorImpl ← 委派模式
├── NativeMethodAccessorImpl ← native 调用(阈值内)
│ └── invoke0(method, obj, args) ← JNI native 调用
│ └── numInvocations > threshold ← 膨胀检测
└── GeneratedMethodAccessorXXX ← 生成的 Java 字节码(JIT 可内联)
java.lang.reflect.Field ← 字段反射
└── getInt(obj) / setInt(obj, val)
└── FieldAccessor
└── UnsafeFieldAccessorImpl ← 基于 Unsafe
└── unsafe.getInt(obj, offset) ← 直接内存读取
└── unsafe.putInt(obj, offset) ← 直接内存写入
java.lang.reflect.AccessibleObject ← 可访问性控制
├── setAccessible(boolean) ← 设置可访问
└── checkAccess(caller, declaringClass) ← JDK 9+ 模块化检查
java.lang.reflect.Array ← 数组反射
├── newInstance(componentType, length) ← 一维数组
└── newInstance(componentType, dimensions) ← 多维数组
sun.reflect.ReflectionFactory ← 反射工厂
├── inflationThreshold() ← 膨胀阈值(默认 15)
└── newConstructorForSerialization(clazz) ← 序列化构造器
└── Unsafe.allocateInstance(clazz) ← 绕过构造器分配内存
java.lang.invoke.MethodHandle ← JDK 7+ 方法句柄
├── invokeExact(args...) ← 精确调用(签名多态)
├── invoke(args...) ← 自动适配调用
└── MethodHandles.Lookup ← 查找上下文(受模块限制)
java.lang.invoke.VarHandle ← JDK 9+ 变量句柄
├── get(obj) / set(obj, val) ← 读写字段
├── getAndAdd(obj, delta) ← 原子自增
└── compareAndSet(obj, expected, new) ← CAS 操作
java.lang.reflect.Type ← 泛型类型体系
├── ParameterizedType ← 参数化类型(List<String>)
├── TypeVariable ← 类型变量(T extends Number)
└── WildcardType ← 通配符类型(? extends Number)总结
Class.forName()是反射的起点:它通过 native 方法加载类并触发<clinit>初始化,与ClassLoader.loadClass()的核心区别在于是否执行静态初始化块。Class.newInstance()已被弃用:JDK 9+ 标记@Deprecated(since="9"),由Constructor.newInstance()替代——后者支持带参构造器、正确处理已检查异常。ReflectionData 软引用缓存:
Class使用SoftReference<ReflectionData>缓存方法/字段/构造器的元信息,在内存不足时可被 GC 回收,兼顾性能与内存安全。Method.invoke() 委派链:
DelegatingMethodAccessorImpl→NativeMethodAccessorImpl(前 15 次 native 调用)→GeneratedMethodAccessor(15 次后生成字节码,JIT 可内联)。膨胀阈值的性能权衡:默认 15 次区分"冷方法"(native 启动快)和"热方法"(字节码 JIT 后更优),通过
-Dsun.reflect.inflationThreshold=可调。setAccessible()受模块系统限制:JDK 9+ 的模块化检查要求跨模块反射必须通过--add-opens开放包,否则抛InaccessibleObjectException。字段读写的底层是 Unsafe:
Field.getInt()/setInt()通过Unsafe.getInt(obj, offset)直接内存读写,一条 CPU 指令级别操作。序列化绕过构造器:
ReflectionFactory.newConstructorForSerialization()基于Unsafe.allocateInstance()创建对象,不调用任何构造器——这是反序列化框架的核心机制。反射性能替代方案:JDK 7+ 的
MethodHandle(接近直接调用)和 JDK 9+ 的VarHandle(原子字段操作)在性能上限上显著优于传统反射。Class.isAssignableFrom()用于运行时类型兼容性检查,与instanceof互补。