You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot+MyBatis中Mapper返回类型与Java声明不一致却正常运行的原因

现象原理拆解:MyBatis返回子类实例匹配父类声明的原因

1. Java泛型的类型擦除机制

Java泛型是编译时语法糖,编译完成后泛型信息会被彻底擦除。你代码里的List<Menu>,编译后会退化为原始类型List。这带来两个关键影响:

  • 编译阶段编译器仅做静态类型检查,只要MenuView是Menu的子类(满足向上转型规则),就不会报错;但它无法约束运行时List中实际存放的实例类型。
  • 运行时JVM不知道泛型的具体类型限制,只要实例是Menu的子类,就能正常存入List,不会触发类型转换异常。

2. MyBatis的对象创建逻辑

MyBatis执行查询时,完全以XML配置的resultType为准来实例化对象:

  • 你在findAll的XML里指定了resultType="MenuView",MyBatis就会通过反射直接创建MenuView实例,再把查询到的所有字段(包括likeCount)填充进去。
  • MyBatis不会校验Mapper接口声明的返回类型(List<Menu>)和resultType是否完全一致,只要两者存在继承/实现关系,就会直接返回该实例。

3. 编译时检查的局限性

编译器只能校验代码语法和静态类型的合法性:

  • 它无法读取MyBatis XML中的resultType配置,只会判断MenuView能否向上转型为Menu(子类转父类是合法的),因此不会抛出编译错误。
  • 这种“接口声明父类、实际返回子类”的写法本身符合Java多态规则,编译器没有理由拦截。

4. 运行时字段/属性的访问逻辑

页面能正常打印likeCount,核心是运行时操作的是MenuView实例:

  • 如果是通过Spring Boot返回JSON到页面,序列化框架(如Jackson)会反射运行时对象的所有字段,不管你代码里声明的是Menu类型,因此likeCount会被正常序列化输出。
  • 即便直接调用getLikeCount()方法,由于运行时对象是MenuView,会触发动态绑定,调用子类的方法(若Menu中无此方法,编译时会报错,能正常运行说明要么Menu有该方法的空实现,要么你是通过反射访问字段)。

内容的提问来源于stack exchange,提问作者unrest7972

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 21:03:19