具有超级意外行为的Java通配符

时间:2014-07-08 10:32:45

标签: java wildcard super

我编写了一个实现Comparable接口的类Fruit和2个子类:Apple和Orange。 我写了一个方法,它返回2个水果之间的最大值(无论它意味着什么)。

请注意,我没有使用任何带有super的通配符。

我认为max方法会失败,因为Comparable接口不是由Apple或Orange直接实现的。

问题: 为什么建议使用这种形式的通配符:

<T extends Comparable<? super T>>

如果它也没有超级工作吗?

以下是代码:

package main;

//Note that I did not use the super wildcard: <T extends Comparable<? super T>>
class Max {

  public static <T extends Comparable<T>> T getMax(T x, T y) {
    return x.compareTo(y) >= 0 ? x : y;
  }
}

class Fruit implements Comparable<Fruit> {
    public String name;

    public Fruit(String name) {
        this.name = name;
    }

    @Override
    public int compareTo(Fruit other) {
        return name.compareTo(other.name) == 0 ? 0 :
               name.compareTo(other.name) > 0 ? 1 : -1;
    }

}

class Apple extends Fruit {
    String name;

    public Apple(String name) {
        super(name);
    }

}

class Orange extends Fruit {
    String name;

    public Orange(String name) {
        super(name);
    }

}

public class Main {

    public static void main(String[] args) {

        Apple a = new Apple("apple");
        Orange o = new Orange("orange");
        Fruit f = Max.getMax(a, o); //It should not be allowed because T does not implement Comparable directly
        System.out.println(f.name);

  }
}

2 个答案:

答案 0 :(得分:2)

在您的情况下,T可以选择Fruit,语句Fruit f = Max.getMax(a, o);可以正确地进行类型检查。因此,它有效。

Max.getMax()的参数类型为TT的子类型实例也是T的实例,因此该方法接受T的任何子类型为参数。

但请注意,您的方法仍有问题,T只能推断为Fruit,而不是Apple,因此您无法返回Apple

Apple a = Max.getMax(apple1, apple2);

但是,请考虑T是泛型类型参数的内容:

public static <T extends Comparable<T>> T getMax(List<T> xs) {
  //...
}

泛型不是协变的,因此此方法只能接受List<Fruit>,但不能接受List<Apple>List<Orange>,即使Apple可以与Apple进行比较等等。

如果您将其更改为:

public static <T extends Comparable<? super T>> T getMax(List<T> xs) {
  //...
}

然后它适用于List<Apple>List<Orange>

答案 1 :(得分:0)

当Fruit实现ComparableApple以及Orange扩展Fruit时,他们只是从compareTo继承Fruit实现。

如果您愿意,可以覆盖AppleOrange子类中的compareTo方法。

我认为这是你对继承的理解,而不是你对>符号的理解。

<T extends Comparable<? super T>>

您在此定义类型T扩展了Comparable,因此您可以安全地在对象上调用compareTo方法。

传递给方法DO的两个对象都具有可比性(因为它们扩展了Fruit,它实现了Comparable)