简体   繁体   English

Java泛型Enum子类型接口

[英]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()? 为什么编译器不接受列表作为accept()的参数?

List extends Iterable via Collection so that isn't the problem. List通过Collection扩展Iterable ,这不是问题。

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> 另一方面,编译器告诉我incompatible types: java.util.List<enums.Constants> cannot be converted to java.lang.Iterable<enums.MyInterface>

But Constants IS a MyInterface... isn't it? 但常量是一个MyInterface ......不是吗?

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. 具体来说,泛型是非规范的......这意味着即使Constants是MyInterface的子类,编译器也不会将Iterable<enum.Constants>看作Iterable<enum.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. 如果将static void accept(Iterable<MyInterface> values)更改为static void accept(Iterable<? extends MyInterface> values) ,它应该可以工作。

You need to use Iterable<? extends MyInterface> 你需要使用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: Iterable<? extends MyInterface>而不是Iterable<MyInterface>因为即使ConstantsMyInterface的子类型, Iterable<Constants>也不是Iterable<MyInterface>的子Iterable<MyInterface> - 我将向您展示原因:

If it was so (let's use List instead of Iterable for the next example), I would be able to do this: 如果是这样(让我们使用List而不是Iterable用于下一个例子),我将能够这样做:

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> Iterable<? extends MyInterface> will allow you to use any Iterable (eg, a List ) of a type that extends MyInterface (eg Constants ). Iterable<? extends MyInterface>将允许你使用任何Iterable (例如,一个List扩展的类型) MyInterface (如Constants )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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