带有通配符的Java自引用泛型

带有通配符的Java自引用泛型,java,generics,wildcard,self-reference,Java,Generics,Wildcard,Self Reference,是否可以指定未知泛型类型是自引用的 失败的尝试: 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 ne

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

失败的尝试:

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));
      }
   }
}
import java.util.*;
类泛型{
公共枚举A{A1,A2}
公共枚举B{B1,B2}
公共静态列表>列表工厂(字符串[]args){
如果(args.length==0){
返回新的ArrayList(Arrays.asList(A.A1,A.A2));
}否则{
返回新的ArrayList(Arrays.asList(B.B1,B.B2));
}
}
公共静态void main(字符串[]args){
列表>lst=列表工厂(args);
dblList(lst);
系统输出打印项次(lst);
}
公共静态void dblList(列表lst){
int size=lst.size();
对于(int i=0;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
Generics.java:17:错误:类泛型中的方法dblList不能应用于给定类型;
dblList(lst);
^
必填项:列表
找到:列表
原因:推断的类型不符合声明的绑定
推断:第1章
绑定:枚举
其中EType是类型变量:
EType扩展方法dblList(List)中声明的枚举
其中CAP#1是一个新类型变量:
CAP#1从捕获扩展了枚举?扩展枚举
1错误
理想情况下,
listFactory()
的返回类型将表示该列表包含自引用泛型类型(其确切类型未知)


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

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

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

如果使用得当,类的用户几乎看不到通配符类型。它们使方法接受它们应该接受的参数,并拒绝它们应该拒绝的参数如果类的用户必须考虑通配符类型,则该类的API可能有问题。


这正是EJ描述的问题的一个很好的例子
listFactory()
实际上只是返回一个
List在Java中,类型参数可以是具体类型、通配符类型或类型变量。具体类型对于您的用例来说不够灵活,通配符不能被约束为自引用(因为通配符的每次出现都可以代表不同的类型)

这就留下了类型变量,这些变量可以被约束为自引用的,但由构造函数或方法的调用方提供,而不是被调用方,因此我们不能只执行以下操作:

<E extends Enum<E>> List<E> listFactory(String[] args);
列表工厂(字符串[]args);
因为有人可能用不正确的类型参数调用它

解决此问题的一种方法是装饰退货类型:

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

}

EnumList<?> listFactory(String[] args);
接口枚举列表扩展列表{
}
EnumList listFactory(字符串[]args);
然后,调用方可以执行以下操作:

EnumList<?> x = listFactory(args);
dblList(x);
enumlistx=listFactory(args);
dblList(x);
其中,dblList使用通配符捕获操作列表:

<E extends Enum<E>> void dblList(List<E> list);
void dblList(列表);
值得注意的是,这使得方法签名的编写变得相当困难,因此只有当所讨论的方法确实需要知道类型是自引用的时,才应该这样做。我之所以提到这一点,是因为您的dblList方法没有,可以简单地写成:

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

相反。

您是否尝试使用
List@DanailAlexiev这是一个非常棘手的用例。另请参见我的建议:使用raw类型,抑制警告-
dblList((List)lst)
,我非常怀疑api是否真的需要如此严格的约束。例如,
EnumSet.allOf
可以有一个宽松的签名

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