java - 在泛型声明中使用“?扩展”时,可以避免 Java 中的参数不匹配吗?
问题描述
我正在尝试制作一个处理(可比较)元素的排序列表的函数。因此,我使用的是 generic <T extends List<? extends Comparable>>
,只要我不需要任何需要<? extends Comparable>
作为输入的特定于列表的操作,它就可以工作。但是在下面的代码片段中(最简单的例子:计算两个排序列表的交集),C.add((Comparable)(A.get(posA)));
编译器拒绝了该行,声称add
需要参数? extends Comparable
,这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)
是有效类型? extends Comparable
?显然强制转换不起作用,我希望例程接受并返回任意可比较对象(整数、字符串、自定义对象等)的列表
解决方案
你没有注意到代码中的所有不安全类型语句,即多个不安全类型转换吗?
你真的有很多。这通常意味着整体方法不正确。
事实上,如果您了解泛型在 Java 中的工作原理,事情并没有那么复杂。
这可以帮助你:
- https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html
- https://docs.oracle.com/javase/tutorial/java/generics/lowerBounded.html
以下是您应该根据实际代码考虑的主要事项: 1) 不要使用原始类型,例如List<? extends Comparable>>
. Comparable
是一个泛型类。2)除了使用上限通配符的 List 声明
之外,您不能添加任何内容。最后一个允许使 List 协变:接受 Foo 和任何子类,但具有先前的限制。所以你不想使用它。
3) 您可以实例化一个泛型,而无需为. 使用for类型会让事情变得更简单。
4)你想尽可能地避免反射。 null
List<? extends Foo>
ArrayList
T
ArrayList
T
Comparable
通过遵循这些想法,您可以编写如下代码:
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
}
推荐阅读
- reactjs - React Select - 将用户输入的文本保留在文本字段中,即使用户在 div 之外单击
- kernel - 在 RHEL 上,如果有新内核,停止并启动而不是重新启动会加载新内核?
- python-3.x - 如何在 Python3 中控制线程执行
- c# - OpenCLTemplate 资源不足
- javascript - 如何使用 react-redux-firebase 禁用离线持久性
- android - Recyclerview 仅显示(并复制)Firebase 实时数据库中的最后一个子项
- javascript - 如何查看用户是否第一次上某条路线?角 2+
- javascript - Javascript:如何显示输入值的总价?
- node.js - 拓扑被破坏/拓扑被关闭 - MongoDB(Mongoose) - Discord.js
- python - Python Pandas 将多个列合并为一个带条件的字典列