Java中未检查类型转换的隐患:从List<Map>到List<Student>的映射问题解析

server/2025/2/11 16:29:14/

为什么你的Java对象中出现未知属性?

  • 问题出现
  • 原因
    • 1. 类型擦除与未检查的类型转换
    • 2. 根本原因:Map到Student的映射缺失
  • 为什么代码没有抛出异常?
  • 解决方案:显式映射Map到Student
      • 方案1. 手动转换
      • 方案2:使用对象映射框架(推荐)
    • 添加泛型检查

问题出现

我在运行这段代码的时候,发现了一个非常奇怪的点。

java">List<Student> Students = (List<Student>) insertMap.get("Student")

首先

  1. insertMap.get("Student") 得到的类型是 List<Map> 类型
  2. 但是这段代码可以运行!
  3. 但是,当我debug时,发现 Students 这了列表集合中子元素并不是Student!而是Map类型。里面出现了非Student类的属性

原因

问题的根源是类型转换未校验Map到对象的映射缺失。通过显式的数据映射(手动或通过框架),可以确保Student对象的属性与数据源一致。

1. 类型擦除与未检查的类型转换

Java的泛型在编译后会经历类型擦除,这意味着List在运行时实际是List<Object>。当你强制将List<Map>转换为List<Student>时,编译器无法在运行时检查元素类型是否匹配。例如:

java">List<Map> rawList = (List<Map>) insertMap.get("Student");
List<Student> students = (List<Student>) rawList; // 此处强制类型转换是危险的!

2. 根本原因:Map到Student的映射缺失

问题核心在于:你没有显式地将Map中的数据转换为Student对象。即使类型转换通过,List中的元素实际仍是Map类型,但这些Map被错误地当成了Student对象。当你试图访问Student的属性时,JVM会尝试从Map中查找与Student字段同名的键值,导致以下问题:

  • 存在不属于Student类的属性:因为Map中可能包含其他键,例如Map有一个address字段,而Student类没有该字段。
  • 属性值类型不匹配:例如Map中的age是字符串类型,而Student的age是整型。

为什么代码没有抛出异常?

强制类型转换在以下情况下不会抛出异常:

  • 运行时的 List 元素类型(Map)和目标元素类型(Student)不被检查。Java 不会对泛型类型进行运行时检查,只会检查容器本身是否为 List 类型。
  • 如果你尝试访问 Student 的方法(如 getName),而 Map 中的内容能够支持这种访问(通过类似反射或动态代理机制),程序可能不会立即出错。

但是,这种行为是一种未定义的运行时行为,可能会导致难以调试的错误。

java">Map<String, Object> map = new HashMap<>();
map.put("name", "Tom");
map.put("age", 18);
map.put("extra", "unexpected"); // 多出的属性

当你将 List 强制转换为 List 时,程序将把 Map 对象当作 Student 对象处理。如果你通过 Students.get(0).getName() 调用 getName() 方法,程序可能会尝试将 Map 的 get(“name”) 的结果返回给你。这实际上是因为 Map 和 Student 混淆了,而不是因为 Map 真正是一个 Student。

因此:

  • 如果 Map 中的键值对恰好与 Student 的属性名一致(如 “name” 和 “age”),程序可能会表现得像是正常运行。
  • 如果 Map 中有额外的键值对(如 “extra”),它们不会被 Student 类直接识别,但它们仍然存在于底层对象中,造成了“有不属于 Student 的属性”的现象。

解决方案:显式映射Map到Student

你需要手动将Map中的数据转换为Student对象。以下是两种常见方法:

方案1. 手动转换

java">List<Map<String, Object>> mapList = (List<Map<String, Object>>) insertMap.get("Student");
List<Student> students = new ArrayList<>();for (Map<String, Object> map : mapList) {Student student = new Student();student.setId((String) map.get("id"));student.setName((String) map.get("name"));// 显式映射其他字段...students.add(student);
}

方案2:使用对象映射框架(推荐)

如果项目中已引入Jackson或Gson,可以直接将Map序列化为JSON,再反序列化为Student对象:

java">
import com.fasterxml.jackson.databind.ObjectMapper;ObjectMapper mapper = new ObjectMapper();
List<Map<String, Object>> mapList = (List<Map<String, Object>>) insertMap.get("Student");
List<Student> students = mapList.stream().map(map -> mapper.convertValue(map, Student.class)).collect(Collectors.toList());

添加泛型检查

如果你需要确保类型安全,可以在获取数据时添加泛型检查,避免直接使用未经检查的类型转换:

java">Object obj = insertMap.get("Student");
if (obj instanceof List<?>) {List<?> list = (List<?>) obj;if (!list.isEmpty() && list.get(0) instanceof Map) {// 进行类型转换}
}

http://www.ppmy.cn/server/166801.html

相关文章

从零开始学Python爬虫:(一)爬虫前言

一、必备知识点 &#xff08;1&#xff09;python基础 想用Python爬虫&#xff0c;首先你要有一定python基础。 关于python基础知识&#xff0c;可以去我的主页找到&#xff1a; 用人话讲计算机系列的Python篇目&#xff0c;共十七节 外附加python知识点精汇系列&#xff…

redis底层数据结构——链表

文章目录 定义内部实现总结 定义 链表提供了高效的节点重排能力&#xff0c;以及顺序性的节点访间方式&#xff0c;并且可以通过增删节点来灵活地调整链表的长度。 作为一种常用数据结构&#xff0c;链表内置在很多高级的编程语言里面&#xff0c;因为Redis使用的C语言并没有…

k8s部署logstash

1. 编写logstash.yaml配置文件 --- apiVersion: v1 kind: Service metadata:name: logstash spec:type: ClusterIPclusterIP: Noneports:- name: logstash-tcpport: 5000targetPort: 5000- name: logstash-beatsport: 5044targetPort: 5044- name: logstash-apiport: 9600targ…

STC 51单片机62——极简 4x4x4光立方

本次设计一个非常简洁的光立方&#xff0c;省略了限流电阻&#xff0c;用两节1.5V干电池直接驱动。 主控芯片&#xff1a;STC8H1K28&#xff0c;属于STC中比较新的系列单片机&#xff0c;管脚够用&#xff0c;也没有很多的空余。 电源直接使用带开关的电池盒&#xff0c;内含2…

后端开发校招面试常见问答总结(一)|Java高频考点解析

1. HashMap底层原理&#xff08;出现频率98%&#xff09; 问题&#xff1a;HashMap如何解决哈希冲突&#xff1f;JDK8做了哪些优化&#xff1f; 回答要点&#xff1a; 数组链表/红黑树结构&#xff08;JDK8后链表长度>8转红黑树&#xff09; 二次哈希计算索引&#xff1a;…

deepseek-r1(Mac版 安装教程)

文章目录 deepseek-r1安装教程&#xff08;Mac&#xff09;1. 安装ollama2. 本地下载对应的模型3. 使用3.1 终端直接使用3.2 网页使用 deepseek-r1安装教程&#xff08;Mac&#xff09; 1. 安装ollama 如果之前没有安装过ollama的&#xff0c;需要在ollama官网下载对应系统的o…

Cocos2d-x 游戏开发-打包apk被默认自带了很多不必要的权限导致apk被报毒,如何在Cocos 2d-x中强制去掉不必要的权限-优雅草卓伊凡

Cocos2d-x 游戏开发-打包apk被默认自带了很多不必要的权限导致apk被报毒&#xff0c;如何在Cocos 2d-x中强制去掉不必要的权限-优雅草卓伊凡 实战操作 去除权限 要在 Cocos2d-x 开发的游戏中去掉 APK 自带权限&#xff0c;可以按照以下步骤操作&#xff1a; 编辑 AndroidMa…

19.1.2 DML

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 DML用于操作数据&#xff0c;例如新增、删除、更新、查询等。 19.1.2.1 北风数据库的使用 打开北风数据库&#xff0c;如果由于安…