一个带有泛型参数的java方法 - 为什么我不能传递一个带有泛型参数的对象,该参数是方法参数的子类?

时间:2010-10-27 17:19:16

标签: java generics

我的意思是,在下面的代码中:

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的对象,它可能需要一个派生对象。这是为什么?

3 个答案:

答案 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.

这就是为什么这段代码不会首先编译的原因。