简体   繁体   English

Java泛型和继承:无法添加到列表

[英]Java Generics & Inheritance: Unable to add to List

Suppose I have a List definition as follows. 假设我有一个List定义,如下所示。

private List<? extends GeneralBudgetYearBean> budgetYearBeans;

// + Getters/setters...

Why am I unable to generally refer to this List as follows outside this class: 为什么在本课之外,我通常无法按以下方式引用此列表:

GeneralBudgetYearBean gbyb;
getBudgetYearBeans().add(bgyb);

The error is: 错误是:

The method add(capture#6-of ? extends GeneralBudgetYearBean) in the type List<capture#6-of ? extends GeneralBudgetYearBean> is not applicable for the arguments (GeneralBudgetYearBean)

This doesn't make sense. 这没有道理。 Is it because "? extends T" is not the same as "T", and "T" can't be substituted here? 是否因为“?extends T”与“ T”不同,并且不能在此处替换“ T”?

I need to be able to generally manipulate this class without specifics. 我需要通常能够在没有细节的情况下操纵此类。 At some point, there will be an ArrayList of "SUBGeneralBudgetYearBeans" constructed in extending classes, which is why I need to use the "? extends GeneralBudgetYearBean" notation. 在某个时候,将在扩展类中构造一个“ SUBGeneralBudgetYearBeans”的ArrayList,这就是为什么我需要使用“?extended GeneralBudgetYearBean”表示法的原因。

According to the PESC principle: 根据PESC原则:

Use extends when only need to get objects and super when only need to add object. 当只需要获取对象时,使用扩展;当只需要添加对象时,使用扩展。

In your case, the 就您而言,

private List<? extends GeneralBudgetYearBean> budgetYearBeans;

is a producer , which means that the list will only be able to produce elements. 生产者 ,这意味着列表将只能产生元素。 The reason is that at compile-time the compiler is not aware of the sub-type of GeneralBudgetYearBean, which is why it doesn't let you add elements, since it's not entirely sure whether to allow you or not. 原因是在编译时,编译器不知道GeneralBudgetYearBean的子类型,这就是为什么它不让您添加元素的原因,因为不能完全确定是否允许您。

Since you will (at some point) also add SubBudgetYearBean objects (which I believe are subclasses of GeneralBudgetYearBean ), you will have to create the list as a consumer . 由于您还将(在某个时候)添加SubBudgetYearBean对象(我相信这是GeneralBudgetYearBean子类),因此您必须将列表创建为使用者 Thus, this will work for you: 因此,这将为您工作:

private List<? super SubBudgetYearBean> budgetYearBeans;

In this case, you will be able to instantiate budgetYearBean as: 在这种情况下,您将能够实例化budgetYearBean为:

budgetYearBeans = new ArrayList<Object>();
budgetYearBeans = new ArrayList<GeneralBudgetYearBean>();

In both of the cases, you will be able to add both GeneralBudgetYearBean and SubBudgetYearBean objects. 在这两种情况下,您都可以添加GeneralBudgetYearBeanSubBudgetYearBean对象。

When you use the expression List<? extends GeneralBudgetYearBean> budgetYearBeans; 当您使用表达式List<? extends GeneralBudgetYearBean> budgetYearBeans; List<? extends GeneralBudgetYearBean> budgetYearBeans; , you tell the compiler that the variable will later receive a List where X will extend GeneralBudgetYearBean . ,您告诉编译器该变量以后将收到一个List,其中X将扩展GeneralBudgetYearBean But it cannot know what class it will be, and as such if will not allow you to add anything into it. 但是它不知道它将是什么类,因此,如果不允许,则不能在其中添加任何内容。

You can make the current class generic : 您可以使当前类通用:

class xxx<T extends GeneralBudgetYearBean> {
    private List<T> budgetYearBeans; // getter and setter

Then you will be allowed to do : 然后,您将被允许做:

T gbyb;
getBudgetYearBeans().add(bgyb);

because now you tell the compiler : you do not know exactly what it will be, but it will be the same thing. 因为现在您告诉编译器:您不完全知道它将是什么,但是会是同一回事。

Drop the wildcards, they won't really help you in this case, they just complicate things unless you really know what you are doing. 删除通配符,在这种情况下它们不会真正为您提供帮助,它们只会使事情复杂化,除非您真的知道自己在做什么。

private List<GeneralBudgetYearBean> budgetYearBeans = ...

public List<GeneralBudgetYearBean> getBudgetYearBeans() {
    return budgetYearBeans;
}

Because SUBGeneralBudgetYearBean extends GeneralBudgetYearBean , then there is no problem with either adding them to the list by one... 因为SUBGeneralBudgetYearBean扩展了GeneralBudgetYearBean ,所以将它们添加到列表中一个都没有问题。

SUBGeneralBudgetYearBean sgyb = ...
getBudgetYearBeans().add(sgyb);

... or as a list... ...或作为清单...

List<SUBGeneralBudgetYearBean> sgybs = ...
getBudgetYearBeans().addAll(sgybs);

See? 看到? No wildcards are actually needed. 实际上不需要通配符。 :) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM