Java递归与反射(求解惑)
-
定义
方法自己调用自己,分为两部分:
递归出口(基线条件):终止递归,避免死循环栈溢出
递归体(递推条件):缩小问题规模,重复调用自身 -
核心规则
必须有出口,否则 StackOverflowError 栈溢出
每次递归参数向出口靠近
适合:阶乘、斐波那契、树遍历、目录遍历、回溯算法 -
基础案例
案例 1:计算 n 的阶乘
java
运行
public class RecursionDemo {
// 递归求阶乘 n! = n*(n-1)!
public static int factorial(int n) {
// 递归出口
if (n == 0 || n == 1) {
return 1;
}
// 递归体
return n * factorial(n - 1);
}public static void main(String[] args) {
System.out.println(factorial(5)); // 120
}
}
案例 2:递归遍历文件夹(文件树)
java
运行
import java.io.File;
public class FileRecursion {
public static void listFile(File dir, int level) {
// 打印缩进层级
for (int i = 0; i < level; i++) System.out.print(" ");
System.out.println(dir.getName());
// 如果是文件夹,继续递归
if (dir.isDirectory()) {
File[] files = dir.listFiles();
if (files != null) {
for (File f : files) {
listFile(f, level + 1);
}
}
}
}
public static void main(String[] args) {
File root = new File("D:/test");
listFile(root, 0);
}
}
4. 优缺点
优点:代码简洁,树形 / 分治问题逻辑清晰
缺点:大量递归深度大时栈溢出;重复计算效率低(可用记忆化优化)
二、反射 Reflection
- 定义
Java 反射机制:程序运行时,动态获取类的完整信息,并操作对象的属性、方法、构造器。
正常编码:编译期确定类 / 方法;反射:运行期动态解析类。 - 反射核心类(java.lang.reflect 包)
Class:类对象,一切反射入口
Constructor:构造方法
Field:成员变量 / 字段
Method:成员方法 - 获取 Class 对象 3 种方式
java
运行
class User {
public String name;
private int age;
public User(){}
public User(String name){this.name = name;}
private void show(){System.out.println(“私有方法”);}
}
public class ReflectGetClass {
public static void main(String[] args) throws ClassNotFoundException {
// 方式1:类名.class
Class c1 = User.class;
// 方式2:对象.getClass()
User u = new User();
Class<? extends User> c2 = u.getClass(); // 方式3:Class.forName("全类名")(最常用,框架底层) Class<?> c3 = Class.forName(“User”);
}
}
4. 反射完整实战:创建对象、读写属性、调用私有方法
java
运行
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectOperate {
public static void main(String[] args) throws Exception {
// 1. 获取Class对象
Class clazz = User.class;
// 2. 通过无参构造创建对象
User user = clazz.newInstance();
// 3. 获取并修改公有字段
Field nameField = clazz.getField("name");
nameField.set(user, "张三");
System.out.println(nameField.get(user));
// 4. 获取私有字段,暴力破解访问权限
Field ageField = clazz.getDeclaredField("age");
ageField.setAccessible(true); // 关闭权限检查
ageField.set(user, 22);
System.out.println(ageField.get(user));
// 5. 调用私有方法
Method showMethod = clazz.getDeclaredMethod("show");
showMethod.setAccessible(true);
showMethod.invoke(user); // 执行方法
}
}
5. 反射优缺点
优点:框架底层核心(Spring、MyBatis、SpringBoot);动态创建对象、解耦;配置文件加载类
缺点:
破坏封装(setAccessible(true) 访问私有)
运行时操作,性能比直接调用低
代码繁琐、可读性差
6. 应用场景
Spring IOC 容器:通过反射创建 Bean 对象
ORM 框架 MyBatis:反射封装数据库实体类
动态代理、注解解析、配置文件加载类
三、递归 vs 反射 核心对比
表格
维度 递归 反射
本质 方法自调用,解决分治 / 树形问题 运行时动态解析、操作类结构
依赖 方法自身逻辑 java.lang.reflect 反射 API
运行阶段 编译期已确定类 / 方法,运行循环调用 运行时动态解析 Class
典型场景 阶乘、树遍历、目录扫描、回溯 框架、动态创建对象、读取私有成员
风险 递归深度过大 → 栈溢出 破坏封装、性能损耗
四、综合案例:递归 + 反射 结合(递归解析实体类所有字段,含父类)
需求:递归向上遍历类及其所有父类,反射打印全部属性名
java
运行
import java.lang.reflect.Field;
public class ReflectRecursionDemo {
static class Person {
private String idCard;
}
static class User extends Person {
private String username;
private Integer score;
}
// 递归打印当前类 + 所有父类字段
public static void printAllField(Class<?> clazz) {
// 递归出口:父类到Object终止
if (clazz == Object.class) {
return;
}
System.out.println("==== " + clazz.getSimpleName() + " 字段 ====");
// 获取本类所有字段(包含私有)
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
System.out.println(f.getType().getSimpleName() + " " + f.getName());
}
// 递归处理父类
Class<?> superCls = clazz.getSuperclass();
printAllField(superCls);
}
public static void main(String[] args) {
printAllField(User.class);
}
}
输出:
plaintext
==== User 字段 ====
String username
Integer score
==== Person 字段 ====
String idCard
逻辑说明
反射:获取当前类的所有成员变量
递归:不断获取父类 getSuperclass(),直到顶层 Object 停止
组合使用场景:工具类递归解析对象完整属性、序列化工具、对象拷贝工具
更多推荐

所有评论(0)