简体   繁体   中英

Java generics Enum subtyping Interface

Given the following setup:

  public class TestType {

  public static void main(String[] args) {
    List<Constants> list = new ArrayList<>();
    accept(list); //Does not compile
  }

  static void accept(Iterable<MyInterface> values) {
    for (MyInterface value : values) {
      value.doStuff();
    }
  }
}

interface MyInterface<T> {
  T doStuff();
}

enum Constants implements MyInterface<Integer> {
  ONE, TWO, THREE;

  @Override
  public Integer doStuff() {
    return ordinal();
  }
}

Why won't the compiler accept the list as parameter to accept()?

List extends Iterable via Collection so that isn't the problem.

On the other hand, the compiler tells me that incompatible types: java.util.List<enums.Constants> cannot be converted to java.lang.Iterable<enums.MyInterface>

But Constants IS a MyInterface... isn't it?

The problem is with how Generics work. Specifically, Generics are non-reified... meaning that the compiler will not see an Iterable<enum.Constants> as an Iterable<enum.MyInterface> even if Constants is a sub-class of MyInterface.

However, there is a way to get around it: Generic wildcards .

If you change static void accept(Iterable<MyInterface> values) to static void accept(Iterable<? extends MyInterface> values) , it should work.

You need to use Iterable<? extends MyInterface> Iterable<? extends MyInterface> instead of Iterable<MyInterface> because even though Constants is a subtype of MyInterface , Iterable<Constants> is not a subtype of Iterable<MyInterface> - and I'll show you why:

If it was so (let's use List instead of Iterable for the next example), I would be able to do this:

List<Constant> constantsList = new ArrayList<Constants>(); // list of constants
List<MyInterface> ifaceList = constantsList; // you said this would be OK ...
// assume MyOtherImplementation is another implmentation of MyInterface
ifaceList.add(new MyOtherImplementation()); // OK, MyOtherImplementation implements MyInterface
Constant myConst = constantsList.get(0); // Oops! I just got an instance of MyOtherImplementation from List<Constant> - not cool.

Generic types do not inherit this way, although it may seem counter-intuitive at first glance. Using Iterable<? extends MyInterface> Iterable<? extends MyInterface> will allow you to use any Iterable (eg, a List ) of a type that extends MyInterface (eg Constants ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM