I'm trying to understand Generic types in Java, and in theory it looks understandable, but when I need to apply it to real code I have problem. I want to declare abstract method which will return generic type. Let's assume that I have some empty interface called Magicable and 2 class implements it: Magican and Witch. Now I wonder what is the difference between those 3 declarations:
/*1*/protected abstract <T extends Magicable> List<T> getMagicables();
/*2*/protected abstract List<? extends Magicable> getMagicables();
/*3*/protected abstract List<Magicable> getMagicables();
In first case I have problem when I want to implement body of this method in some class which extends the abstract class:
@Override protected List<Magican> getMagicable() {..}
I have warning message:
Type safety: The return type List<Magican> for getMagicable() from the type MagicanService needs unchecked conversion to conform to List<Magicable> from the type MagicableService.
In second case I don't have this warning, but I have problem in abstract class in which I declared above abstract method:
public void <T extends Magicable> T getOneFromList() { List<T> list = getMagicables(); //..... }
In this case I have compilation error in getMagicables() call:
Type mismatch: cannot convert from List<capture#2-of ? extends Magicable> to List<T>
Third case causes compilation errors in both abovementioned places of code. I don't think if it is properly solution in my case.
- First case
Just declare your method with:
@Override
protected <T extends Magicable> List<T> getMagicables() {
List<T> list = ...
return list
}
If you really want this:
@Override
protected List<Magican> getMagicable() {..}
you may have to declare your generic T into the class defintion
public abstract class AbstractKlass<T extends Magicable> {
protected abstract List<T> getMagicables();
}
then in your Subclass:
public class MySubClass extends AbstractKlass<Magican> {
@Override
protected List<Magican> getMagicables() {
...
}
}
- Second case
The compilation error is normal because <? extends Magicable>
from the signature of method means you don't care what's inside your list from the moment you can consider those elements just as Magicable. When doing a call
List<T> list = getMagicables();
You want to take care of the type T without knowing it. In other terms, there are 3 use cases: T is Magicable (OK), T is Magician (Wrong because getMagicables may return a list of Witch) and T is Witch (Wrong too).
- Why I use
? extends Magicable
instead of justMagicable
in lists
Because List<Magician>
is a subtype of List<? extends Magicable>
but not a subtype of List<Magicable>
. This is usefull for parameters of methods.
public void doIt(List<? extends Magicable> list) {
// you can't add a Magician here
}
may be used as
List<Witch> list = ...
doIt(list);
But if you have
public void doIt(List<Magicable> list) {
// you can add a Magician here
}
You can't use it as
List<Witch> list = ...
doIt(list); // compile error