Java 17中使用ModelMapper出现类型不匹配的困惑
问题解析:Java泛型擦除导致的类型安全异常场景
问题描述
使用Java 17搭配ModelMapper时出现违背直觉的类型行为:将List<Test>类型的转换结果添加到ArrayList<Boolean>中,代码不仅能编译通过,还能正常执行并输出混合了Test对象和Boolean值的列表。
代码复现
import java.util.ArrayList; import java.util.List; import org.modelmapper.ModelMapper; import com.google.gson.reflect.TypeToken; public final class ModelMapperAdapter { private static ModelMapper MODEL_MAPPER; public static class Test{ Integer var; // getter、setter省略 } public static void main(String[] args) { MODEL_MAPPER = new ModelMapper(); Test test = new Test(); List<Test> list = new ArrayList<>(); List<Boolean> ids = new ArrayList<>(); list.add(test); ids.addAll(MODEL_MAPPER.map(list, new TypeToken<List<Test>>(){}.getType())); System.out.println(ids);// [ModelMapperAdapter.Test(var=null)] ids.add(true); System.out.println(ids);// [ModelMapperAdapter.Test(var=null), true] } }
核心原因:Java泛型的类型擦除机制
- 编译时检查,运行时擦除:Java泛型是编译期特性,编译后所有泛型类型信息会被擦除,
List<Boolean>和List<Test>在运行时都会被视为原始类型List。 - 未经检查的类型转换:
ModelMapper.map()方法返回的是Object类型,调用addAll()时,编译器仅做形式上的类型兼容校验,不会验证传入集合的实际元素类型是否与目标列表泛型匹配,直接放行未经检查的类型转换。 - 运行时的原始类型兼容:因为
List在运行时是原始类型,本质上存储的是Object对象,所以添加Test实例和Boolean值都不会触发类型转换异常,只有当你尝试将列表元素强制转换为Boolean时,才会抛出ClassCastException。
解决方案
- 显式指定类型转换逻辑:先获取正确类型的转换结果,再手动实现
Test到Boolean的映射,让编译器做严格类型检查:List<Test> mappedList = MODEL_MAPPER.map(list, new TypeToken<List<Test>>(){}.getType()); // 根据业务需求实现Test到Boolean的转换逻辑,示例:判断var是否非空 List<Boolean> ids = mappedList.stream() .map(test -> test.getVar() != null) .collect(Collectors.toList()); - 启用编译警告:编译时添加
-Xlint:unchecked参数,让编译器提示未经检查的类型转换操作,提前发现这类潜在风险。
内容的提问来源于stack exchange,提问作者Piyush Maheshwari
相关产品推荐
相关产品推荐

