我正在做一些Java学习,特别是在泛型领域。
我对 C# 中的泛型相当熟悉,但在 Java 中,情况完全不同。
我使用了一些测试效果很好的示例,并且我能够在 Java 中很好地复制大部分 C# 代码。
但是,当我尝试以下示例时,它不起作用:
private static <T> void swapKundeData(ArrayList<T> data, int index1, int index2) {
T temporary = (T) data.get(index1);
data.set(index1, data.get(index2)); //Does not compile
data.set(index2, temporary); //Does not compile
}
我收到的错误是:
ArrayList 类型中的 set(int, capture#5-of ? extends ExtendTest) 方法不适用于参数 (int, ExtendTest)
这在 C# 中也能正常工作 - 那么发生了什么?
我了解到 Java 在泛型方面受到了很多批评。这是批评的一部分吗?数据变量的删除和添加方法工作得很好。
嗯,我会用
List<Kunde>
而不是
ArrayList<?>
既然你无论如何都要选昆德语:)。
它不起作用的原因是你不知道传递的对象的类型。因此,如果您设置的 Kunde 可能是错误的类型(因为使用 ArrayList < ? >,您可以传递 ArrayList < String > 并在其上设置 Kunde 将是错误的类型)。
另一种可能性是:
private static <T> void swapData(List<T> data, int index1, int index2) {
T temporary = data.get(index1);
data.set(index1, data.get(index2)); //Does compile
data.set(index2, temporary); //Does compile
}
为了完成我的咆哮,只需使用 Collections 的交换方法即可。
http://download.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html#swap(java.util.List, int, int)
如果你知道你的
ArrayList
包含 Kunde
对象,那么你应该声明方法参数 ArrayList<Kunde>
;无需使用通配符。 正如您所看到的,它会导致编译时类型错误。
请参阅 http://download.oracle.com/javase/tutorial/extra/generics/wildcards.html 了解问题的完整说明。
问题的原因是您声明了一种
ArrayList<?>
类型,这意味着“一个列表应该只包含某种类型,但我不知道是哪一种”。结果是,关于从列表中取出的对象,您唯一知道的是它们是 Object
类型,因为一切都是(除了基元,它不能在集合中)。但更重要的是,您不能将 anything 放入列表中,因为您不知道它被约束为什么类型。
这就是为什么使用
?
通配符很少合适。在几乎所有情况下,您应该使用具体类型或命名有界类型:
private static void swapKundeData(List<Kunde> data, int index1, int index2) {
Kunde temporary = data.get(index1);
data.set(index1, data.get(index2));
data.set(index2, temporary);
}
注意
List
接口的使用,这使得代码接受的内容更加灵活。
private static <T> void swap(List<T> data, int index1, int index2) {
T temporary = data.get(index1);
data.set(index1, data.get(index2));
data.set(index2, temporary);
}
这是真正的通用解决方案,它是类型安全的,但不需要知道列表元素是什么类型。实际上,通过在这里使用泛型,您实际上并没有真正获得任何类型安全性(
Object
也可以),但是您可以例如返回交换的元素之一,编译器会知道返回值与列表元素的类型相同。
我注意到该问题已被编辑,因此之前的答案没有多大意义。
从问题编辑来看,值得注意的是,如果您希望客户看到如下方法:
public static void swapKundeData(List<?> data, int index1, int index2) {
但是你想实现:
public static <T> void swapKundeData(List<T> data, int index1, int index2) {
可以捕获通配符,并且具有客户端友好形式的方法可以转发到实现友好形式:
public static void swapKundeData(List<?> data, int index1, int index2) {
swapKundeDataImpl(data, index1, index2)
}
private static <T> void swapKundeDataImpl(List<T> data, int index1, int index2) {
(我假设“kunde”不是一个粗鲁的词。)
总结一下奥利所说的,你不能分配给“未知类型”'?'的集合。因为java不知道里面应该放什么。 然而,由于每个“未知类型”仍然是一个对象,因此在其上调用“getter”方法是安全的,因为它们总是返回一个 Object 类型的对象。
问题出在 Eclipse 上。
我没有保存文件,所以显然没有重新编译任何内容。
哇,这个 IDE 的无能和烦恼(例如速度)给我留下了深刻的印象。
哦,好吧。