Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 254
tannerli Avatar asked Feb 12 '16 14:02

tannerli


People also ask

Can enum be generic Java?

Java enums will be enhanced with generics support and with the ability to add methods to individual items, a new JEP shows. Since both features can be delivered with the same code change, they are bundled together in the same JEP. The change only affects the Java compiler, and therefore no runtime changes are needed.

Can we use generics in interface?

Generics make a class, interface and, method, consider all (reference) types that are given dynamically as parameters. This ensures type safety. Generic class parameters are specified in angle brackets “<>” after the class name as of the instance variable. Generic constructors are the same as generic methods.

What is subtyping in Java?

What is subtyping? Subtyping is a key feature of object-oriented programming languages such as Java. In Java, Sis a subtype of T if S extends or implements T. Subtyping is transitive, meaning that if R is a subtype of S, then R is also a subtype of T (T is the super type of both Sand R).

Is it a good idea to use generics in collections?

By using generics, programmers can implement generic algorithms that work on collections of different types, can be customized, and are type safe and easier to read.


2 Answers

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.

like image 141
Powerlord Avatar answered Oct 15 '22 04:10

Powerlord


You need to use 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.
like image 34
Jiri Tousek Avatar answered Oct 15 '22 06:10

Jiri Tousek