Java Generic中的通配符和<! - ?超级T - >意思是,下限或上限

时间:2013-12-10 15:03:23

标签: java generics wildcard extends bounded-wildcard

所以我正在阅读泛型方法,我感到困惑。我先说一下这个问题:

在这个例子中:假设我需要一个适用于任何类型T的selectionSort版本,方法是使用调用者提供的外部可比较。

首次尝试:

public static <T> void selectionSort(T[] arr, Comparator<T> myComparator){....}

假设我有:

  • 定义的车辆类
  • 创建了实现Comparator的VehicleComparator 比较车辆的价格。
  • 创建卡车扩展车辆
  • 实例化Truck [] arr; VehicleComparator myComparator

现在,我这样做:

selectionSort(arr, myComparator);

并且它不起作用,因为myComparator不适用于Vehicle的任何子类。

然后,我这样做:

public static <T> void selectionSort(T[] arr, Comparator<? super T> myComparator){....}

这个宣言可行,但我不完全确定我一直在做什么......我知道使用是要走的路。如果“?super T”的意思是“一个未知的超类型T”,那么我是强加上限还是上限?为什么超级?我的目的是让T的任何子类使用myComparator,为什么“?super T”。如此困惑......如果您对此有任何见解,我将不胜感激。

提前致谢!

4 个答案:

答案 0 :(得分:5)

首先,您可以通过Vehicle[]Truck添加到其中来解决问题。

您需要<? super T>的原因可以追溯到Comparator<Truck>不是Comparator<Vehicle>的子类型的泛型规则;无界类型T必须完全匹配,而不是。

为了传入合适的Comparator,它必须是被比较的类的Comparator或它的任何超类,因为在OO语言中,任何类都可以被视为超类的实例。因此,Comparator的泛型类型无关紧要,只要它是数组组件类型的超类型。

答案 1 :(得分:3)

古怪的短语? super T表示目的地列表可能包含任何类型的元素 这是T的超类型,就像源列表可能包含任何类型的元素一样 T的子类型。

我们可以从copy看到非常简单的示例Collections

public static <T> void copy(List<? super T> dst, List<? extends T> src) {
   for (int i = 0; i < src.size(); i++) {
    dst.set(i, src.get(i));
   }
}

并致电:

List<Object> objs = Arrays.<Object>asList(2, 3.14, "four");
List<Integer> ints = Arrays.asList(5, 6);
Collections.copy(objs, ints);
assert objs.toString().equals("[5, 6, four]");

与任何通用方法一样,可以推断出类型参数,也可以明确给出。在这种情况下,有四种可能的选择,所有选择都是类型检查,所有选择都具有相同的效果:

Collections.copy(objs, ints);
Collections.<Object>copy(objs, ints);
Collections.<Number>copy(objs, ints);
Collections.<Integer>copy(objs, ints);

答案 2 :(得分:2)

您的选择排序方法

public static <T> void selectionSort(T[] arr, Comparator<? super T> myComparator)

表示如果使用类型为T的数组调用它,则必须提供类型为T的ComparatorT的超类型。

例如,如果您有以下类

class Vehicle {}

class Truck extends Vehicle {}

class BigTruck extends Truck {}


class VehicleComparator implements Comparator<Vehicle> {

    public int compare(Vehicle o1, Vehicle o2) {
        return 0;
    }
}
class BigTruckComparator implements Comparator<BigTruck> {
    public int compare(BigTruck o1, BigTruck o2) {
        return 0;
    }
}

class TruckComparator implements Comparator<Truck> {
    public int compare(Truck o1, Truck o2) {
        return 0;
    }
}

比这更有用

Truck[] trucks = ...;
selectionSort(trucks, new TruckComparator());
selectionSort(trucks, new VehicleComparator());

因为

  • TruckComparator实现Comparator<Truck>Truck等于数组的类型Truck
  • VehicleComparator实现Comparator<Vehicle>Vehicle是数组类型的超级类型Truck

这将不工作

selectionSort(trucks, new BigTruckComparator());

你现在应该猜到为什么。

因为BigTruckComparatorComparator<BigTruck>BigTruck不是数组类型Truck的超类型。

答案 3 :(得分:1)

两个签名在权力方面是等价的 - 对于任何一组参数,如果存在适用于其中一个的类型参数的选择,则存在可用于另一个的类型参数的选择,并且反之亦然。

您只是在编译器中遇到有限的推断。只需明确指定所需的类型参数:

YourClass.<Vehicle>selectionSort(arr, myComparator);