应将java.sql.Date等JDBC日期类型自动转为java.util.Date后再反射赋值:判断field类型为util.Date且value为sql子类时,用getTime()构造新util.Date实例,再调用Field.set()。

Java 反射设置实体属性时,若数据库字段是 DATE 类型(JDBC 返回 java.sql.Date),而实体类对应字段是 java.util.Date,直接用 Field.set() 会抛 IllegalArgumentException:类型不匹配。这不是反射本身的问题,而是类型强校验导致的。要实现“无缝转换”,关键在于**在赋值前自动识别并完成 SQL 类型到 Java 通用类型的适配**。
判断字段类型并做兼容性转换
在通过反射设置属性前,先检查目标 Field 的声明类型是否为 java.util.Date,再检查待设值是否为 java.sql.Date、java.sql.Timestamp 或 java.sql.Time 等子类,然后统一转为 java.util.Date:
-
java.sql.Date→ 调用getTime()构造new java.util.Date(sqlDate.getTime()) -
java.sql.Timestamp→ 同样用getTime()(它继承自java.util.Date,但精度更高;转成util.Date会丢失纳秒,通常可接受) -
java.sql.Time→ 若业务允许,也可转(但语义不同,慎用) - 其他类型(如
String、Long)按需扩展,比如 ISO 格式字符串可解析为util.Date
封装通用的 setFieldValue 方法
避免每次手动判断,建议封装一个安全的反射赋值工具方法:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
public static void setFieldValue(Object target, Field field, Object value) throws IllegalAccessException {
if (value == null) {
field.set(target, null);
return;
}
Class<?> fieldType = field.getType();
// 如果字段是 java.util.Date,且值是 sql 子类,则转换
if (fieldType == java.util.Date.class) {
if (value instanceof java.sql.Date || value instanceof java.sql.Timestamp || value instanceof java.sql.Time) {
value = new java.util.Date(((java.util.Date) value).getTime());
}
}
// 其他类型转换(如 Boolean/boolean 自动装拆箱等)可在此扩展
field.setAccessible(true);
field.set(target, value);
}
配合 ResultSet 使用时的典型场景
在 ORM 工具或手写 DAO 中遍历 ResultSet 映射对象时,调用上述方法即可:
立即学习“Java免费学习笔记(深入)”;
- 用
rs.getObject(colIndex)获取值(推荐,能保持原始 JDBC 类型) - 不要用
rs.getDate()直接返回java.sql.Date再硬塞给util.Date字段 - 获取字段名后通过
Class.getDeclaredField()找到对应属性,再调用封装好的setFieldValue()
注意事项与替代思路
该方案轻量、无依赖,适合简单映射场景。但要注意:
-
java.sql.Date仅包含日期(年月日),时分秒为 0;转换后仍是“零点时刻”的util.Date,语义一致 - 如果实体字段是
LocalDate(Java 8+),应优先转为LocalDate,而非util.Date(更现代、线程安全) - Spring JDBC、MyBatis 等框架已内置此类转换,无需重复造轮子;自研框架或极简场景才需手动处理
- 若使用 Jackson 或 FastJSON 做 JSON 序列化,注意它们默认对
util.Date和sql.Date的序列化行为不同,需统一配置


















