如何向带有限定通配符的泛型类传递具体实例?
TLDR;
为什么无法将接口的实现类实例传递给用限定通配符初始化的泛型类,以统一处理多种负载?
完整问题
假设需要处理一些JSON负载,它们拥有通用的包装结构,仅在已知结构的部分属性上存在差异,示例如下:
{ "id": "object-one", "timestamp": "...", "payloadType": "ConcreteClassA", "payload": { "classAProperty": "barfoo" } } { "id": "object-one", "timestamp": "...", "payloadType": "ConcreteClassB", "payload": { "classBProperty": 42 } }
现在有一个泛型类,需要处理这两种具体类型,因此使用限定通配符指定它仅处理该接口的实现类。请问如何向该类的方法传递具体类的实例?忽略了什么?
interface CommonInterface { } class ConcreteClassA implements CommonInterface { String classAProperty; } class ConcreteClassB implements CommonInterface { int classBProperty; } class Wrapper <WrappedType extends CommonInterface>{ void doSomethingWithWrappedType(WrappedType wrappedObject) { // do something with wrappedObject } } class Example { void doSomeThingWrapped() { Wrapper<? extends CommonInterface> wrapper = new Wrapper<>(); wrapper.doSomethingWithWrappedType(new ConcreteClassA()); // <-- 此处报错:需要capture of ? extends CommonInterface,提供的是ConcreteClassA } }
问题根源
Wrapper<? extends CommonInterface> 表示这个Wrapper的泛型类型是某个未知的CommonInterface子类——它可能是ConcreteClassA,也可能是ConcreteClassB,甚至是其他未定义的实现类。编译器无法确定这个未知类型具体是什么,所以不允许你传入任何具体子类实例:毕竟如果这个Wrapper实际是Wrapper<ConcreteClassB>,传入ConcreteClassA显然是错误的。
解决方案
根据需求,有三种常见处理方式:
- 直接指定泛型为CommonInterface
如果doSomethingWithWrappedType方法只需要调用CommonInterface中定义的方法,不依赖子类特有属性,直接把泛型类型设为CommonInterface即可:
void doSomeThingWrapped() { Wrapper<CommonInterface> wrapper = new Wrapper<>(); wrapper.doSomethingWithWrappedType(new ConcreteClassA()); wrapper.doSomethingWithWrappedType(new ConcreteClassB()); }
- 修改方法参数为CommonInterface
若希望Wrapper兼容所有CommonInterface实现类,同时保留泛型灵活性,可以调整方法签名,直接接受CommonInterface类型参数:
class Wrapper <WrappedType extends CommonInterface>{ void doSomethingWithWrappedType(CommonInterface wrappedObject) { // 安全调用CommonInterface的方法 } }
这样不管Wrapper的泛型类型是什么,都能传入任何CommonInterface实现类。
- 使用泛型方法替代类泛型
如果需要在方法中保持类型一致性,可以把方法定义为泛型方法,去掉类的泛型声明:
class Wrapper { <T extends CommonInterface> void doSomethingWithWrappedType(T wrappedObject) { // 可使用T的类型信息,同时接受所有CommonInterface子类 } }
总结
你之前的错误在于用? extends CommonInterface限定Wrapper的泛型类型,但这种通配符主要用于读取操作(比如从Wrapper中获取元素),而非写入操作(向方法传入元素)。如果需要写入,要么明确指定泛型为CommonInterface,要么调整方法参数类型。
内容的提问来源于stack exchange,提问作者Peter C. Glade
相关产品推荐
相关产品推荐

