Java类型转换错误:无法将Supplier<S>转换为Supplier<?>问题求助
Java类型转换错误:无法将Supplier转换为Supplier<?>问题求助
兄弟,我看你这段代码应该是编译的时候卡壳了——就是往registry里放registry_value那行,编译器报错说没法把Supplier<Statement<R>>转成Supplier<Statement<?>>对吧?我先把你没写完的代码补全,方便咱捋清楚问题:
public class StatementRegister { public static final Map<String, Supplier<Statement<?>>> registry = new HashMap<>(); public static <R> Supplier<Statement<R>> register(String id, Supplier<Statement<R>> statement) { Supplier<Statement<R>> registry_value = () -> statement.get().withID(id); registry.put(id, registry_value); // 这里就是报错的核心位置 return registry_value; } }
为啥会报这个错呢?其实是Java泛型的不变性在搞事情。你可能觉得「既然Statement<R>是Statement<?>的子类型,那对应的Supplier也应该能直接兼容」,但Java泛型默认是不变的——换句话说,Supplier<Statement<R>>和Supplier<Statement<?>>在编译器眼里是完全不相关的类型,哪怕它们的泛型参数有继承关系。
给你两个靠谱的解决办法:
- 方案一:调整注册表的泛型声明(推荐)
把registry的类型改成支持协变的通配符形式,这样就能直接容纳Supplier<Statement<R>>了:
// 把泛型改成Supplier<? extends Statement<?>> public static final Map<String, Supplier<? extends Statement<?>>> registry = new HashMap<>();
这个改法最安全,完全符合泛型的设计规范,不会有任何警告。
- 方案二:显式类型转换(适合不能改注册表类型的场景)
如果因为某些原因不能改registry的声明,那可以做一个安全的显式转换,同时加注解抑制编译器的警告(咱自己确认转换是安全的就行):
public static <R> Supplier<Statement<R>> register(String id, Supplier<Statement<R>> statement) { Supplier<Statement<R>> registry_value = () -> statement.get().withID(id); // 先转成Supplier<?>再转目标类型,避免直接转换的硬报错 @SuppressWarnings("unchecked") Supplier<Statement<?>> typedValue = (Supplier<Statement<?>>) (Supplier<?>) registry_value; registry.put(id, typedValue); return registry_value; }
另外还有个小细节:你可以检查下Statement类里的withID方法返回值类型是不是Statement<R>?如果它不小心返回了Statement<?>,那registry_value的类型自动就变成Supplier<Statement<?>>,也不会有这个问题了。
备注:内容来源于stack exchange,提问作者slit bodmod
相关产品推荐
相关产品推荐

