记一次Java反射的简单使用方式

背景

在更新数据库记录时,如果提供的实体对象除了主键 id 外,其他字段都为 null,那么生成的 SQL 语句可能会缺少 SET 子句,导致语法错误。例如:

UPDATE am_dept WHERE id=?

为了避免这种情况,我们需要检查实体对象中是否有除 id 外的非 null 字段。如果有,则执行更新操作;如果没有,则跳过更新,防止生成错误的 SQL 语句。

代码解析

我们来看这段代码:

import java.lang.reflect.Field;

// ...

boolean hasNonNullField = false;
Field[] fields = optPo.getClass().getDeclaredFields();

for (Field field : fields) {
    field.setAccessible(true);
    // 跳过 id 字段
    if ("id".equals(field.getName())) {
        continue;
    }
    Object value = field.get(optPo);
    if (value != null) {
        hasNonNullField = true;
        break;
    }
}

if (hasNonNullField) {
    deptPoService.update(optPo);
} else {
    log.warn("没有需要更新的字段,跳过更新操作,部门ID:{}", optPo.getId());
}
1. 导入反射包
import java.lang.reflect.Field;

这行代码导入了 java.lang.reflect.Field 类,允许我们在运行时获取类的字段信息,并对子段进行操作。

2. 初始化标识变量
boolean hasNonNullField = false;

这里声明了一个布尔变量 hasNonNullField,初始值为 false。它用于标记 optPo 对象中是否存在除 id 外的非 null 字段。

3. 获取所有声明的字段
Field[] fields = optPo.getClass().getDeclaredFields();
  • optPo.getClass():获取 optPo 对象的运行时类。
  • getDeclaredFields():获取该类中所有声明的字段,包括私有字段,返回一个 Field 数组。
4. 遍历所有字段
for (Field field : fields) { // ... }

使用增强型 for 循环遍历每个字段 field

5. 设置字段可访问
field.setAccessible(true);
  • 反射默认无法访问私有字段,setAccessible(true) 方法可以设置字段的可访问性,允许访问私有字段。
6. 跳过 id 字段
if ("id".equals(field.getName())) { continue; }
  • field.getName():获取字段的名称。
  • 如果字段名为 "id",则跳过本次循环,不进行后续操作。
  • 因为 id 是主键,不需要检查其值。
7. 获取字段值
Object value = field.get(optPo);
  • field.get(optPo):获取 optPo 对象中当前字段的值。
  • 返回值是一个 Object 对象。
8. 判断字段值是否为非 null
if (value != null) { hasNonNullField = true; break; }
  • 如果字段值不为 null,说明此字段有需要更新的值。
  • 将 hasNonNullField 设置为 true
  • 使用 break 结束循环,因为已经找到一个非 null 的字段,后续无需再检查。
9. 根据检查结果决定是否执行更新操作
if (hasNonNullField) {
    deptPoService.update(optPo);
} else {
    log.warn("没有需要更新的字段,跳过更新操作,部门ID:{}", optPo.getId());
}
  • 如果 hasNonNullField 为 true,说明存在需要更新的字段,执行更新操作。
  • 如果 hasNonNullField 为 false,则记录一条警告日志,提示没有需要更新的字段,跳过更新操作。

为什么要使用反射?

在这个场景中,我们需要检查对象中是否有非 null 的字段。手动逐一检查每个字段可能比较繁琐,尤其是当字段数量较多时。反射提供了一种动态获取类信息的方式,可以在运行时获取对象的所有字段及其值。

使用反射的优势:

  • 动态性:无需预先知道对象有哪些字段,代码对字段的变化具有更好的适应性。
  • 通用性:可以适用于任何类的对象,不必为每个类编写特定的检查代码。

注意事项

  1. 性能开销

    • 反射操作相比直接访问字段,性能会有所降低。但对于大多数应用场景,这种影响是可以忽略的。
    • 如果在高性能要求的场景下,需要优化这部分代码,可以考虑其他方式。
  2. 安全性

    • 使用 setAccessible(true) 可能会违反封装原则,破坏了类的封装性。
    • 在受控的环境下(如内部应用),这种方式是可行的。但在对安全性要求较高的环境下,需谨慎使用。
  3. 可维护性

    • 反射代码可能在调试和维护时增加一些负担,需要开发者对反射机制有一定的了解。

总结

这段代码通过反射机制,动态地获取 optPo 对象的所有字段,然后检查每个字段的值是否为非 null,以确定是否需要执行更新操作。

  • 核心逻辑

    • 获取所有字段(除 id 外)的值。
    • 如果存在任意一个字段的值不为 null,则表示有需要更新的内容。
    • 根据是否有需要更新的内容,决定是否执行更新操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值