Java传递参数化Map类参数报错及两种反序列化实现差异问题
问题1:如何传入带泛型参数的Map类型
出现cannot select from parameterized type报错的核心原因是Java泛型采用类型擦除实现,运行期不存在Map<String,Commit>.class这种参数化类型的Class对象,只有原始类型Map.class。有两种解决方式:
- 方式1:直接传入原始类型Class,调用后手动强转
调用代码示例:
// 会触发unchecked cast编译警告,确认序列化存储的对象确实是Map<String, Commit>类型可忽略 Map<String, Commit> result = (Map<String, Commit>) Utils.readObject(new File("asd"), Map.class);
- 方式2:新增TypeReference实现保留泛型信息(类型更安全)
先定义TypeReference抽象类:
public abstract class TypeReference<T> { private final Type type; protected TypeReference() { ParameterizedType superClass = (ParameterizedType) getClass().getGenericSuperclass(); this.type = superClass.getActualTypeArguments()[0]; } public Type getType() { return type; } }
在工具类中重载readObject方法:
public static <T extends Serializable> T readObject(File file, TypeReference<T> typeRef) { try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) { return (T) in.readObject(); } catch (IOException | ClassNotFoundException e) { throw new IllegalArgumentException(e.getMessage()); } }
调用代码示例:
Map<String, Commit> result = Utils.readObject(new File("asd"), new TypeReference<Map<String, Commit>>() {});
问题2:原有readObject返回null、自定义实现正常的原因
你观察到的返回null现象本质不是原有readObject方法自身返回null,而是逻辑差异导致:
- 原有readObject的异常处理逻辑是捕获异常后直接抛出IllegalArgumentException,如果你的上层调用代码捕获了该异常却没有做抛出/日志处理,而是直接返回null,就会出现你看到的返回null现象。而你自定义的实现只有触发异常时才返回null,正常反序列化后直接返回Object对象,调用时手动强转不会触发额外的异常抛出逻辑。
- 原有readObject中包含
expectedClass.cast()的强校验步骤:如果序列化存储的实际类型和你传入的expectedClass不兼容(比如你存的是HashMap却传入了SortedMap.class),会触发ClassCastException,进而抛出IllegalArgumentException,也会导致上层拿到null。你自定义的实现完全跳过了类型校验,只要对象可以强转为目标类型就可以正常运行。 - 检查两次调用的路径是否一致:你原有调用传入的是
new File("asd"),自定义实现调用传入的是Utils.join(dir, "commits"),如果路径不一致导致原有方法读不到对应文件,会触发IO异常抛出,最终上层也会拿到null。
内容的提问来源于stack exchange,提问作者yemen
相关产品推荐
相关产品推荐

