news 2026/9/5 8:43:05

P08 · ClassCastException:类型强转翻车,Integer 变不成 String

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
P08 · ClassCastException:类型强转翻车,Integer 变不成 String

P08 · ClassCastException:类型强转翻车,Integer 变不成 String

场景还原:一段从老项目继承来的代码,用"原始类型 List"装数据(为了省事没写泛型)。后来你接手,把它当成List<String>用——结果运行时炸了:

java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String

编译的时候好好的,一运行就崩。这正是泛型擦除给你埋的雷:编译期检查的"类型安全",到了运行期变成了"信不信由你"。

一、问题现象

注: CastDemo.java使用了未经检查或不安全的操作。 ← 编译时就警告你了 第一个元素: 你好 Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap') at CastDemo.main(CastDemo.java:14)

二、出错代码

importjava.util.*;publicclassCastDemo{publicstaticvoidmain(String[]args){List<String>list=newArrayList<>();// 老代码 / 反射 / JSON 反序列化里容易混入"原始类型"用法:Listraw=list;// 原生类型 List(没写泛型)raw.add("你好");raw.add(123);// ❌ 往"以为是 String"的列表里塞了 IntegerStringfirst=list.get(0);// 没问题,"你好"本来就能转成 StringSystem.out.println("第一个元素: "+first);Stringsecond=list.get(1);// ← 这里炸了:Integer 无法强转成 StringSystem.out.println("第二个元素: "+second);}}

三、为什么会这样

核心原因一句话:Java 的泛型在运行期会被"擦除"

List<String> list里的<String>只在编译期起作用——编译器用它做类型检查(往里面 add 一个 Integer 在编译期会被拦住)。但编译成字节码后,这个类型信息就没了,运行期的List就是一个"什么都能装的桶"。

于是这段代码干了这么件事:

  1. 先用原生类型List raw = list绕过了编译期检查,成功把Integer 123塞了进去;
  2. 运行期list.get(1)返回的其实是Object(指向 Integer 123);
  3. 代码里声明了String second = ...,JVM 在赋值时悄悄插入了强转(String)
  4. 一个 Integer 怎么可能变成 String?→ClassCastException

谁最常踩这个坑

  • 老代码 / 历史遗留的"原始类型集合";
  • JSON 反序列化(Gson/Jackson 没指定泛型时,反序列化出的 List 里元素类型不可信,取出来强转随时炸);
  • 反射调用返回 Object 后随手强转;
  • 泛型与继承混用(List<String>不是List<Object>的子类这类问题)。

四、怎么解决

原则:让类型从源头就干净,别把"类型安全"寄托在运行期的强转上。

方案一:杜绝原始类型,全程写泛型

List<String>list=newArrayList<>();list.add("你好");// list.add(123); // ✅ 编译期直接报错,根本活不到运行期

方案二:从"不可信来源"(JSON/反射)取数据时,先校验再强转

Objectobj=map.get("age");// JSON 解析出来的 Objectif(objinstanceofInteger){// ✅ 先 instanceof 判断intage=(Integer)obj;}else{// 类型不对,走兜底/报错,而不是直接崩溃System.out.println("age 字段类型不是数字: "+obj);}

方案三:JSON 反序列化一定带上明确的泛型

// Gson:TypeToken 保住泛型List<User>users=newGson().fromJson(json,newTypeToken<List<User>>(){}.getType());// Jackson:TypeReference 同理List<User>users2=objectMapper.readValue(json,newTypeReference<List<User>>(){});

五、防坑总结

  • 代码里出现"裸 List/Map"(没泛型)就是隐患,尽早补上泛型;
  • 编译器的"未经检查的操作"警告别忽略,它是在提醒你这里类型不安全;
  • 从 JSON/反射拿到 Object 先instanceof再强转;
  • 集合别跨"类型假设"传递(一个 List 被当两种类型用,早晚出事);
  • 强转失败看异常信息:X cannot be cast to Y,说的是 X 转不成 Y——去源头查谁把 X 塞进来的。

下一篇:P09 · 数字转换 NumberFormatException

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 8:39:21

Fable 5.1系统卡安全披露:Agent隐蔽任务与监控盲区分析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/5 8:32:48

档案数字化研发手记:档案管理系统整体架构——单体还是微服务?

一、为什么档案系统经常纠结架构 档案管理系统有个特点&#xff1a;业务不复杂&#xff0c;但部署环境复杂。 有的客户是省级档案馆&#xff0c;要求信创环境、等保三级、异地容灾&#xff1b;有的客户是县级档案馆&#xff0c;一台服务器、内网、无外网&#xff1b;有的客户是…

作者头像 李华
网站建设 2026/9/5 8:27:54

Canal架构与工作原理:MySQL Binlog解析、增量订阅与消费链路详解

Canal架构与工作原理&#xff1a;MySQL Binlog解析、增量订阅与消费链路详解 1. Canal架构概述 Canal是阿里巴巴开源的基于MySQL数据库增量日志解析的组件&#xff0c;它伪装成MySQL的从节点&#xff0c;解析binlog日志&#xff0c;并将变更数据实时推送到下游。Canal的设计目标…

作者头像 李华
网站建设 2026/9/5 8:27:06

基于Cyclone III FPGA与USB3.0的DDR2高速数据采集系统设计与调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/5 8:25:29

Roblox TypeScript技能系统开发:从角色建模到网络同步实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华