我的 Java 泛型测试不起作用!

问题描述 投票:0回答:6

我正在做一些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 在泛型方面受到了很多批评。这是批评的一部分吗?数据变量的删除和添加方法工作得很好。

java generics
6个回答
6
投票

嗯,我会用

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)


2
投票

如果你知道你的

ArrayList
包含
Kunde
对象,那么你应该声明方法参数
ArrayList<Kunde>
;无需使用通配符。 正如您所看到的,它会导致编译时类型错误。

请参阅 http://download.oracle.com/javase/tutorial/extra/generics/wildcards.html 了解问题的完整说明。


1
投票

问题的原因是您声明了一种

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
也可以),但是您可以例如返回交换的元素之一,编译器会知道返回值与列表元素的类型相同。


1
投票

我注意到该问题已被编辑,因此之前的答案没有多大意义。

从问题编辑来看,值得注意的是,如果您希望客户看到如下方法:

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”不是一个粗鲁的词。)


0
投票

总结一下奥利所说的,你不能分配给“未知类型”'?'的集合。因为java不知道里面应该放什么。 然而,由于每个“未知类型”仍然是一个对象,因此在其上调用“getter”方法是安全的,因为它们总是返回一个 Object 类型的对象。


0
投票

问题出在 Eclipse 上。

我没有保存文件,所以显然没有重新编译任何内容。

哇,这个 IDE 的无能和烦恼(例如速度)给我留下了深刻的印象。

哦,好吧。

© www.soinside.com 2019 - 2024. All rights reserved.