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

时间:2021-08-22 20:45:33

What I mean is, in the code below:

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

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
    }
}

But if the function simply took an object of base, it could take a derived object. Why is this?

但是如果函数只是采用了base的对象,那么它可能需要一个派生对象。为什么是这样?

3 个解决方案

#1


14  

func needs to be defined as

func需要定义为

public void func(List<? extends base> list) { ... }

This is because a List<derived> is not actually a List<base>, because a List<base> allows any kind of base in it, while a List<derived> only allows derived and its subclasses. Using ? extends base ensures that you can't add anything but null to the List, since you're not sure what subclasses of base the list might allow.

这是因为List 实际上不是List ,因为List 允许其中包含任何类型的base,而List 仅允许派生及其子类。用? extends base确保您不能向List添加任何空值,因为您不确定列表可能允许的基类的哪些子类。

As an aside, you should try to follow standard Java naming conventions... classes starting with lowercase letters look strange, like they're primitives.

顺便说一下,你应该尝试遵循标准的Java命名约定......以小写字母开头的类看起来很奇怪,就像它们是原始的一样。

#2


4  

This is because if passing in a List<derived> was allowed, func() would be able to add base-typed elements to the list, thus invalidating the generic contract of the list (which should only allow for derived-typed contents)

这是因为如果允许传入List ,则func()将能够将基类型元素添加到列表中,从而使列表的通用契约无效(这应该只允许派生类型的内容)

if on the other hand you define func as

另一方面,如果你将func定义为

public void func(List<? extends base> list)

you can still retrieve base-typed elements from list, but just won't be able to add any new elements to it, which is exactly the behavior you want.

您仍然可以从列表中检索基本类型的元素,但只是无法向其添加任何新元素,这正是您想要的行为。

#3


0  

To explain this behaviour of java, look at this example

要解释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.

That's why this code will not compile in the first place.

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

#1


14  

func needs to be defined as

func需要定义为

public void func(List<? extends base> list) { ... }

This is because a List<derived> is not actually a List<base>, because a List<base> allows any kind of base in it, while a List<derived> only allows derived and its subclasses. Using ? extends base ensures that you can't add anything but null to the List, since you're not sure what subclasses of base the list might allow.

这是因为List 实际上不是List ,因为List 允许其中包含任何类型的base,而List 仅允许派生及其子类。用? extends base确保您不能向List添加任何空值,因为您不确定列表可能允许的基类的哪些子类。

As an aside, you should try to follow standard Java naming conventions... classes starting with lowercase letters look strange, like they're primitives.

顺便说一下,你应该尝试遵循标准的Java命名约定......以小写字母开头的类看起来很奇怪,就像它们是原始的一样。

#2


4  

This is because if passing in a List<derived> was allowed, func() would be able to add base-typed elements to the list, thus invalidating the generic contract of the list (which should only allow for derived-typed contents)

这是因为如果允许传入List ,则func()将能够将基类型元素添加到列表中,从而使列表的通用契约无效(这应该只允许派生类型的内容)

if on the other hand you define func as

另一方面,如果你将func定义为

public void func(List<? extends base> list)

you can still retrieve base-typed elements from list, but just won't be able to add any new elements to it, which is exactly the behavior you want.

您仍然可以从列表中检索基本类型的元素,但只是无法向其添加任何新元素,这正是您想要的行为。

#3


0  

To explain this behaviour of java, look at this example

要解释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.

That's why this code will not compile in the first place.

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