繁体   English   中英

使用通配符的Java自引用泛型

[英]Java Self-Referential Generics With Wildcards

是否可以指定未知泛型类型是自引用的?

尝试失败:

import java.util.*;

class Generics {
   public enum A { A1, A2 }
   public enum B { B1, B2 }

   public static List<? extends Enum<?>> listFactory(String[] args) {
      if (args.length == 0) {
         return new ArrayList<A>(Arrays.asList(A.A1, A.A2));
      } else {
         return new ArrayList<B>(Arrays.asList(B.B1, B.B2));
      }
   }

   public static void main(String[] args) {
      List<? extends Enum<?>> lst = listFactory(args);
      dblList(lst);
      System.out.println(lst);
   }

   public static <EType extends Enum<EType>> void dblList(List<EType> lst) {
      int size = lst.size();
      for (int i = 0; i < size; i++) {
         lst.add(lst.get(i));
      }
   }
}

这会导致编译错误:

Generics.java:17: error: method dblList in class Generics cannot be applied to given types;
      dblList(lst);
      ^
  required: List<EType>
  found: List<CAP#1>
  reason: inferred type does not conform to declared bound(s)
    inferred: CAP#1
    bound(s): Enum<CAP#1>
  where EType is a type-variable:
    EType extends Enum<EType> declared in method <EType>dblList(List<EType>)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Enum<?> from capture of ? extends Enum<?>
1 error

理想情况下, listFactory()的返回类型将表示该列表包含自引用泛型类型(其确切类型未知)。

这可能吗? 如果是这样, listFactory()lst的类型应该是什么?

有效的Java Item 28不鼓励在返回类型中使用通配符:

不要将通配符类型用作返回类型。 它不会为您的用户提供额外的灵活性,而是迫使他们在客户端代码中使用通配符类型。

正确使用的通配符类型对于类的用户几乎是不可见的。 它们使方法接受它们应该接受的参数并拒绝它们应该拒绝的参数。 如果类的用户必须考虑通配符类型,那么类的API可能有问题。

这是EJ描述的问题的一个很好的例子。 listFactory()实际上只是返回一个List<Enum<?>>但是通过声明一个通配符返回类型,你必须跳过箍来完成看似简单的任务。

如果你给listFactory()一个像这样的签名:

public static List<Enum<?>> listFactory(String[] args)

您也可以清理dblList()的签名:

public static <E> void dblList(List<E> lst)

在Java中,类型参数是具体类型,通配符类型或类型变量。 具体类型对于您的用例来说不够灵活,并且通配符不能被约束为自引用(因为每次出现的通配符都可以代表不同的类型)。

这会留下类型变量,它可以被约束为自引用,但是由构造函数或方法的调用者提供,而不是被调用者,所以我们不能只做:

<E extends Enum<E>> List<E> listFactory(String[] args);

因为有人可能会使用不正确的类型参数调用它。

解决此问题的一种方法是修饰返回类型:

interface EnumList<E extends Enum<E>> extends List<E> {

}

EnumList<?> listFactory(String[] args);

然后呼叫者可以:

EnumList<?> x = listFactory(args);
dblList(x);

dblList使用通配符捕获来操作列表:

<E extends Enum<E>> void dblList(List<E> list);

值得注意的是,这使得方法签名更难写,因此只有在所讨论的方法实际需要知道类型是自引用时才应该这样做。 我提到这个是因为你的dblList方法没有,并且可以简单地写成:

<E> void dblList(List<E> list);

代替。

暂无
暂无

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

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