Reputation: 86935
I'd like to have a method in one of my services that should return a generic list. Then I want to add items to that list from another service.
class Fruit;
class Apple extends Fruit;
class FruitService() {
private ArrayList<? extends Fruit> getList() {
return new ArrayList<Apple>();
}
}
class SomeService() {
init() {
fruitService.getList().add(new Apple());
}
}
This gives the following error:
The method add(capture#3-of ? extends Fruit) in the type ArrayList<capture#3-of ? extends Fruit> is not applicable for the arguments (Apple)
Why? How could I add an Apple to that generic list?
My goal is to have that getList() method not to return a specific implementation.
Upvotes: 1
Views: 229
Reputation: 63955
You can't.
ArrayList<? extends Fruit>
could be in fact an
ArrayList<Apple>
in which you can't insert a Banana
although Banana extends Fruit
. And you can't insert a Fruit
because it has to be at least something that extends Apple
. And since Java can't see the required type anymore but has to guarantee that it would work it won't even allow you to insert an Apple
although that would be allowed for the actual list.
-> You can't insert anything into List<? extends Whatever>
besides null
because you don't know the exact type. ? extends Whatever
results in a read-only list of Whatever
.
If you want to return a regular & useful List
don't return one with wildcard types.
Instead you could use generics in FruitService
e.g.
class FruitService<T extends Fruit> {
private ArrayList<T> getList() {
return new ArrayList<T>();
}
public void useList(T fruit) {
getList().add(fruit);
}
}
class User {
void foo() {
FruitService<Apple> appleService = new FruitService<Apple>();
appleService.useList(new Apple());
FruitService<Banana> bananaService = new FruitService<Banana>();
bananaService.useList(new Banana());
}
}
Upvotes: 4
Reputation: 51030
You could make the method generic -
public <T extends Fruit> List<T> getList() {
//....
The type variable T
can capture the actual type argument, so the compiler can assume type-safety.
Also, you can do return new ArrayList<T>();
instead of return new ArrayList<Apple>();
.
Upvotes: 2
Reputation: 42834
Can you have your getList()
method return a List
(or ArrayList
) of Fruit
instead? That way, you can insert any subtype of Fruit
into the List
.
private List<Fruit> getList() {
return new ArrayList<Fruit>();
}
Upvotes: 2