我有一个关于将子类列表分配给超类列表的基本问题。
所以我有以下内容:
Class B extends A;
List <B> bList = new ArrayList<B>();
List <A> aList = bList;
为什么最后一次分配失败?对不起新手问题
答案 0 :(得分:9)
当您声明类型A的项目列表时,只能在列表中添加或删除类型A的项目。如果需要包含A的子类,请使用通用通配符? extends A
来表示。因此,您的代码应为:
List <? extends A> aList = bList;
答案 1 :(得分:9)
为了解释这一点,让我用“整数”替换“B”,用“数字”替换“A”。这只是为了让它更容易解释。
Class Integer extends Number;
List <Integer> iList = new ArrayList<Integer>();
List <Number> nList = iList // will fail
这会失败的原因是因为nList可以取任何数字 - 它可以取整数,它可以取Double,或者就任何子类的Number而言。但是,对于iList,情况并非如此。您不能将Double添加到iList,因为它只接受Integer及其子类。希望这有助于向您解释。
答案 2 :(得分:2)
List<B>
不是List<A>
:
通过示例:假设您有class B1 extends A{}
和class B2 extends A{}
然后(如果你能做到这一点:
List<B1> b1 = new AList<B1>();
List<A> a = b1;
List<B2> b2 = new AList<B2>();
根据假设,你应该能够做到 a.add(新B2()) 但这是错误的。
如果您尝试使用arrays
而不是列表来尝试相同的操作,它将在运行时编译并抛出异常。
我们说数组是协变,而泛型是不变的。
要使代码编译,你就有了它:
List<? extends A> a = b;
这表示a是A的某些子类型的列表。但是你不知道哪一个。因此你不能做a.put(X)
答案 3 :(得分:1)
List<B>
和List<A>
是invariant
类型。您需要的是covariant
类型。在这种情况下,它是List<? extends A>
。
答案 4 :(得分:0)
因为泛型是严格类型安全。
你可以拥有
List<? extends A> aList = bList;
它说aList
可以保存任何类型的列表A
答案 5 :(得分:0)
因为List<B>
没有延伸List<A>
。例如,Integer
扩展Number
,Long
也扩展List<Number>
。因此Integer
可以包含Long
和List<Integer>
。因此,如果您将List<Number>
分配给Long
,则可以将List<? super B> superB;
添加到整数列表中。
您可以声明
aList=bList
这将允许分配包含B及其超类的任何列表的superB。
但这与你的案例List<? extends A> extendsA;
不一样。
或
List<? super Integer> superA;
superA = new ArrayList<Number>();
List<? extends Number> extendsNumber;
extendsNumber = new ArrayList<Integer>();
实施例
{{1}}
答案 6 :(得分:0)
乍一看,你可能会认为
Class B extends A;
List <B> bList = new ArrayList<B>();
List <A> aList = bList;
应该有效,当您想象实际使用这些列表时问题是显而易见的:
A something = new A();
aList.add( something ); // Should work because aList is a list of A's
但aList
已分配给bList
,因此应与
bList.add( something ); // Here's the problem
bList.add()
需要B
,something
为A
,而A
不是B
!
这就是为什么泛型应该(并且是)严格类型安全的原因。