带有通配符的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);