1

Suppose I have a List definition as follows.

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?

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.

gene b.
  • 10,512
  • 21
  • 115
  • 227

3 Answers3

0

According to the PESC principle:

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.

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. Thus, this will work for you:

private List<? super SubBudgetYearBean> budgetYearBeans;

In this case, you will be able to instantiate budgetYearBean as:

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

In both of the cases, you will be able to add both GeneralBudgetYearBean and SubBudgetYearBean objects.

Community
  • 1
  • 1
Konstantin Yovkov
  • 62,134
  • 8
  • 100
  • 147
0

When you use the expression List<? extends GeneralBudgetYearBean> budgetYearBeans;, you tell the compiler that the variable will later receive a List where X will extend 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.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
0

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 sgyb = ...
getBudgetYearBeans().add(sgyb);

... or as a list...

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

See? No wildcards are actually needed. :)

Natix
  • 14,017
  • 7
  • 54
  • 69
  • No, not the case. In an extending class I have to do this: setBudgetYearBeans(new ArrayList()). This gives an error. – gene b. Oct 09 '14 at 15:49
  • Don't use a setter for the list then. Just use `getBudgetYearBeans().clear()` and then `getBudgetYearBeans().addAll(subBudgetBeans)`. – Natix Oct 09 '14 at 15:56