我正在尝试创建一个处理(可比较)元素的排序列表的函数。因此,我使用的是通用的<T extends List<? extends Comparable>>
,只要我不需要任何需要使用<? extends Comparable>
作为输入的特定于列表的操作,它就可以工作。但是在下面的代码片段中(最简单的示例:计算两个排序列表的交集),C.add((Comparable)(A.get(posA)));
行被编译器拒绝,声称add
需要参数? extends Comparable
,{{1 }}显然不是。
Comparable
我应该如何告诉编译器public static <T extends List<? extends Comparable>> T intersect (T A, T B) {
T C = (T) A.getClass().newInstance();
int posA = 0;
int posB = 0;
while(posA<A.size()&&posB<B.size()) {
if (A.get(posA).compareTo(B.get(posB))>0) posB++;
else if (A.get(posA).compareTo(B.get(posB))<0) posA++;
else if (A.get(posA).equals(B.get(posB))) {
C.add((Comparable)(A.get(posA)));
posA++; posB++;
}
}
return C;
}
是有效类型A.get(posA)
?显然,转换不起作用,我希望例程接受并返回任意可比较对象(整数,字符串,自定义对象等)的列表
答案 0 :(得分:4)
您是否没有注意到代码中所有不安全的类型语句,其中多个不安全的类型转换?
你真的有很多。这通常意味着整体方法不是正确的方法。
实际上,如果您学习泛型在Java中的工作原理,事情并不会那么复杂。
那可以帮助您:
以下是根据实际代码应考虑的主要事项:
1)不要使用诸如List<? extends Comparable>>
之类的原始类型。 Comparable
是泛型类。
2)您不能在声明为null
的列表中添加List<? extends Foo>
以外的任何内容,即使用上限通配符。最后一个允许使List成为协变量:接受Foo和任何子类,但有先前的限制。所以你不想使用它。
3)您可以实例化通用ArrayList
,而无需声明T
的通用方法类型ArrayList
。将T
用于Comparable
类型将使事情变得更加简单。
4)您要尽可能避免反射。
按照这些想法,您可以编写如下代码:
public static <T extends Comparable<T>> List<T> intersect (List<T> A, List<T> B) {
List<T> list = new ArrayList<>();
int posA = 0;
int posB = 0;
while(posA<A.size()&&posB<B.size()) {
if (A.get(posA).compareTo(B.get(posB))>0) posB++;
else if (A.get(posA).compareTo(B.get(posB))<0) posA++;
else if (A.get(posA).equals(B.get(posB))) {
list.add(A.get(posA));
posA++; posB++;
}
}
return list;
}
那是我最初的方法,但是这里的问题是,不是每一个 两个非ArrayList列表的交集将是一个ArrayList 在这里。
如果您为参数声明List
,则在编译时将不知道List的类型。因此,您不可避免地要进行不安全的转换。
例如:
@SuppressWarnings("unchecked")
public static <T extends Comparable<T>, L extends List<T>> L intersect(L A, L B) {
if (A.getClass() != B.getClass()) {
throw new IllegalArgumentException("not same type between ...");
}
List<T> list = A.getClass()
.newInstance(); // uncheck
int posA = 0;
int posB = 0;
while (posA < A.size() && posB < B.size()) {
if (A.get(posA)
.compareTo(B.get(posB)) > 0)
posB++;
else if (A.get(posA)
.compareTo(B.get(posB)) < 0)
posA++;
else if (A.get(posA)
.equals(B.get(posB))) {
list.add(A.get(posA));
posA++;
posB++;
}
}
return (L) list; // uncheck
}
答案 1 :(得分:1)
这是一个典型的泛型问题。
您说的是您接受扩展Comparable的所有对象列表。
因此,另一种方法将List传递给您的方法将是完全可以的。
当然,即使扩展了Comparable,也不应允许您在代码中向该列表添加数字!
您可以通过在方法签名中添加另一个通用参数而不是“?”来解决此问题。然后,您可以在代码中强制转换为该参数。