java 反射

Java 反射(Reflection)可以一句话概括为:在运行时"反过来"查看和操作类、方法、字段、构造器等元数据的能力。它是很多框架(Spring、MyBatis、Jackson)的底层基石。

下面用面试 + 实战角度帮你系统梳理。

一、反射能干什么?(核心能力)

能力 示例

运行时获取类信息 类名、修饰符、父类、接口

运行时创建对象 clazz.newInstance() / constructor.newInstance()

运行时调用方法 method.invoke(obj)

运行时读写字段 field.get(obj) / field.set(obj)

绕过访问权限 访问 private 成员

二、获取 Class 对象的三种方式(必会)

// 1. 类名.class(最常用,编译期已知)

Class<?> clazz1 = User.class;

// 2. 对象.getClass()

User user = new User();

Class<?> clazz2 = user.getClass();

// 3. Class.forName()(最灵活,框架最爱)

Class<?> clazz3 = Class.forName("com.example.User");

✅ 区别

• forName:会触发类加载 + 静态代码块

• .class:不会立即初始化

三、反射常用 API(重点)

1️⃣ 构造方法(Constructor)

Constructor ctor =

User.class.getDeclaredConstructor(String.class, int.class);

ctor.setAccessible(true); // 突破 private

User user = ctor.newInstance("Tom", 18);

2️⃣ 字段(Field)

Field field = User.class.getDeclaredField("age");

field.setAccessible(true);

int age = (int) field.get(user);

field.set(user, 20);

3️⃣ 方法(Method)

Method method = User.class.getDeclaredMethod("sayHello", String.class);

method.setAccessible(true);

Object result = method.invoke(user, "World");

四、反射 vs new(面试高频)

对比项 new 反射

编译期检查 ✅ 有 ❌ 无

性能 快 慢(有开销)

灵活性 低 极高

安全性 高 可被绕过

典型场景 普通业务 框架、插件

✅ 结论

• 业务代码:禁止滥用反射

• 框架代码:必须使用反射

五、反射在框架中的真实用途

Spring

• @Autowired:反射注入字段

• @ComponentScan:扫描包 → Class.forName

• AOP:反射 + 动态代理

MyBatis

• 反射读取实体字段 → SQL 映射

• 反射调用 setter / getter

Jackson

• JSON → Java 对象(反射创建 + 赋值)

六、反射的安全与性能问题(重点)

1️⃣ 安全问题

field.setAccessible(true); // 破坏封装

❗ 可能绕过安全检查,甚至修改 final 字段(JDK 9+ 受限)

2️⃣ 性能问题

• 方法调用比直接调用 慢 10~100 倍

• 解决方案:

• 缓存 Method / Field / Constructor

• 使用 sun.misc.Unsafe(极端场景)

• 使用 LambdaMetafactory(Spring 5+)

七、JDK 9 之后的变化(容易被忽略)

• 模块化(JPMS)

• 反射访问非导出包会被拒绝

• 需要 --add-opens

• setAccessible 受限

• 强封装模式下默认禁止

八、反射 + 注解(实战组合)

@Retention(RUNTIME)

@Target(FIELD)

@interface Column {

String value();

}

class User {

@Column("user_name")

private String name;

}

Field field = User.class.getDeclaredField("name");

Column column = field.getAnnotation(Column.class);

System.out.println(column.value()); // user_name

✅ 这是 ORM / 校验框架 的核心原理。

九、面试高频问题(可直接背)

✅ 反射是如何破坏单例的?

→ 通过私有构造器 + setAccessible(true)

✅ 反射为什么慢?

→ 方法查找、权限检查、参数装箱、JVM 优化困难

✅ 如何防止反射攻击单例?

→ 在构造器中判断实例是否已存在并抛异常

✅ 反射和动态代理的关系?

→ 动态代理底层依赖反射调用方法

相关推荐
Lhappy嘻嘻2 小时前
Java IO|File 文件操作 + 字节流 / 字符流完整笔记 + 递归删除文件实战
java·笔记·php
科技道人3 小时前
记录 默认置灰/禁用 app ‘Search Engine Selector‘ 的disable按钮
开发语言·前端·javascript
伊玛目的门徒3 小时前
试用leetcode之典中典 二数之和问题
java·算法·leetcode
逝水无殇5 小时前
C# 异常处理详解
开发语言·后端·c#
懒鸟一枚6 小时前
深入理解 Linux 内存、Swap 交换分区与分页机制的关系
java·linux·数据库
玖玥拾6 小时前
C# 语言进阶(十五)C# 游戏服务端 MySQL 数据库
服务器·开发语言·网络·数据库·mysql·c#
铅笔侠_小龙虾7 小时前
Rust 学习目录
开发语言·学习·rust
我命由我123457 小时前
执行 Gradle 指令报错,无法将“grep”项识别为 cmdlet、函数、脚本文件或可运行程序的名称
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
考虑考虑7 小时前
Sentinel安装
java·后端·微服务
云泽8087 小时前
从零吃透 C++ 异常:抛出捕获、栈展开、异常重抛与编码规范详解
开发语言·c++·代码规范