The difference between using wildcards in Java and declaring generic types in abstract methods
I tried to understand generic types in Java, which seemed understandable in theory, but I encountered problems when I needed to apply it to real code I want to declare an abstract method that will return a generic type Let's assume that I have an empty interface called magic, which is implemented by two classes: magic and witch
/*1*/protected abstract <T extends Magicable> List<T> getMagicables(); /*2*/protected abstract List<? extends Magicable> getMagicables(); /*3*/protected abstract List<Magicable> getMagicables();
>In the first case, when I want to implement the body of this method in a class that extends an abstract class, I encounter a problem:
@Override protected List<Magican> getMagicable() {..}
I have a warning message:
>In the second case, I don't have this warning, but I have a problem in the abstract class. I declare the abstract method above:
public void <T extends Magicable> T getOneFromList() { List<T> list = getMagicables(); //..... }
In this case, I have a compilation error in the getmagicables() call:
>The third case causes compilation errors at the above two code locations In my case, I don't think it's solved correctly
Solution
Simply declare your method:
@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 the generic t as a class definition
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() { ... } }
Compilation errors are normal because from the signature of a method means that you don't care about the contents of the list, from the moment you can treat these elements as magic On the phone
List<T> list = getMagicables();
You want to take care of type T without knowing it In other words, there are three use cases: t is magic (OK), t is a magician (error, because getmagic may return the witch list), and t is Witch (also wrong)
Because list < magician > is list & lt;? The subtype of extends magic > but is not a subtype of list < magic > This is useful for method parameters
public void doIt(List<? extends Magicable> list) { // you can't add a Magician here }
Can 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
List<Witch> list = ... doIt(list); // compile error