Difference between using wildcards and declaring generic type in abstract method in Java

pumbosha :

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();
  1. 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.

  2. 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>

  3. Third case causes compilation errors in both abovementioned places of code. I don't think if it is properly solution in my case.

Max :
  1. 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() {
           ...
        }
     }
  1. 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).

  1. Why I use ? extends Magicable instead of just Magicable 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

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=461358&siteId=1