我的意思是,在下面的代码中:
class base {
}
class derived extends base {
}
class WTF {
public void func(List<base> list) {
}
public void tryit() {
func(new List<base>()); // ok
func(new List<derived>()); // not ok
}
}
但是如果函数只是一个base的对象,它可能需要一个派生对象。这是为什么?
答案 0 :(得分:14)
func
需要定义为
public void func(List<? extends base> list) { ... }
这是因为List<derived>
实际上不是List<base>
,因为List<base>
允许base
中的任何List<derived>
,而derived
只允许? extends base
及其子类。使用null
可确保您无法向List
添加除base
之外的任何内容,因为您不确定列表可能允许的{{1}}的哪些子类。
顺便说一下,你应该尝试遵循标准的Java命名约定......以小写字母开头的类看起来很奇怪,就像它们是原语一样。
答案 1 :(得分:4)
这是因为如果传入List&lt; derived&gt;如果被允许,func()将能够将基类型元素添加到列表中,从而使列表的通用契约无效(这应该只允许派生类型的内容)
另一方面,如果将func定义为
public void func(List<? extends base> list)
您仍然可以从列表中检索基本类型的元素,但只是无法向其中添加任何新元素,这正是您想要的行为。
答案 2 :(得分:0)
要解释java的这种行为,请看这个例子
void addItem(List<Base> list) {
list.add(new Base());
}
List<Base> l1 = new ArrayList<Base>();
addItem(l1);
Base b = l1.get(0);
List<Derived> l2 = new ArrayList<Derived>();
addItem(l2);
Derived d = l2.get(0); // Would cause runtime exception.
这就是为什么这段代码不会首先编译的原因。