使用上边界通配符时不兼容的类型
我真的很困惑上界类型在Javagenerics中是如何工作的。
比方说我有
interface IModel interface I class A implements I class B implements I class C implements I
那么我有一个带参数的方法如下
foo(IModel<Map<? extends I, Map<? extends I, List>>> dataModel)
调用那个方法就像
IModel<Map<A, Map<B, List>>> model = ... foo(model)
以编译错误结束
Error:(112, 49) java: incompatible types: IModel<java.util.Map<A,java.util.Map<B,java.util.List>>> cannot be converted to IModel<java.util.Map<? extends I,java.util.Map<? extends I,java.util.List>>>
我已经从Oracle网络上阅读了关于Javagenerics的文档,试图谷歌它,但必须有一些我完全被误解的东西。
这个问题可以缩短为什么
foo(IModel
> dataModel)
不能接受这样的论点
IModel
> model
说明
List
是List extends I>
的子类型List extends I>
List extends I>
,所以没关系:
public void bar(List extends I> list); List listA; bar(listA);
但是,它不会使IModel
成为>
IModel
的子类型>
IModel
>
IModel
,就像>
IModel
不是IModel
的子类型一样 ,所以你发布的代码无法编译。
解
您可以将其更改为:
foo(IModel extends Map extends I, ? extends Map extends I, ? extends List extends I>>>> dataModel)
要么
void foo(IModel
使它编译。
首先,我想知道你(一个人)要以这种forms整理代码需要付出多少努力:
import java.util.List; import java.util.Map; interface IModel {} interface I {} class A implements I {} class B implements I {} class C implements I {} public class UpperBounds { public static void main(String[] args) { IModel
而不是让数百人(想要帮助你)自己做这件事,以便拥有他们可以编译并在他们的IDE中查看的东西。 我的意思是,这并不难。
话虽如此: 从技术上讲 ,你在这里错过了一些extends
条款。 编译好:
import java.util.List; import java.util.Map; interface IModel {} interface I {} class A implements I {} class B implements I {} class C implements I {} public class UpperBounds { public static void main(String[] args) { IModel>>> model = null; foo(model); } static void foo(IModel extends Map extends I, ? extends Map extends I, ? extends List extends I>>>> dataModel) { } }
但你应该
不
像那样实现它。 那太模糊了。 无论这个dataModel
参数是什么,你都应该考虑为它创建一个合适的数据结构,而不是传递如此混乱的深嵌套通用映射。
原始版本未编译的原因已在其他答案中提及。 通过使用更简单的方法调用显示示例,可以使其更清晰。 考虑这个例子:
interface IModel {} interface I {} class A implements I {} class B implements I {} class C implements I {} public class UpperBounds { public static void main(String[] args) { List> lists = null; exampleA(lists); // Error exampleB(lists); // Works! } static void exampleA(List> lists) { } static void exampleB(List extends List extends I>> lists) { } }
exampleA
方法不能接受给定的列表,而exampleB
方法可以接受它。
详细解释了generics类型的实例化中存在哪些超子类型关系? Angelika Langer撰写的仿制药常见问题解答。
直观地说,关键点是类型List
是List extends I>
的子类型List extends I>
List extends I>
。 但是让该方法只接受List
>
List
不允许你传入一个列表,其元素是>
List extends I>
子类型List extends I>
List extends I>
。 为了接受亚型,你必须使用? extends
? extends
。
(这甚至可以进一步简化:当一个方法接受List
,你就不能传入List
。但这不会使List
成为List extends I>
的子类型List extends I>
清楚这里)
方法method1(Map aMap>)
和A是实现I的类不允许您使用Map
调用该方法,这是有原因的。
有方法:
public static void foo2(IModel dataModel) { System.out.println("Fooing 2"); }
想象一下这段代码:
IModel simpleModel = new IModel() {}; foo2(simpleModel);
这不应该起作用,因为您为需要generics类型的方法提供了更具体的类型。 现在假设foo2执行以下操作:
public static void foo2(IModel dataModel) { dataModel = new IModel() {}; System.out.println("Fooing 2 after we change the instance"); }
在这里,您将尝试将IModel设置为有效的IModel – 因为B扩展了I,但是如果您能够使用IModel调用该方法,那么它将无法工作
创建您的模型,如:
IModel>>> model = ...
并在相应的地图和列表中添加有效的A,B和C类型的对象,然后调用函数foo(model)