当前位置: 代码迷 >> java >> 下限通配符(Comparable <?super K>)
  详细解决方案

下限通配符(Comparable <?super K>)

热度:81   发布时间:2023-07-31 11:28:41.0

在集合中,经常使用Comparable接口,例如。 PriorityQueue

private static <T> void siftUpComparable(int k, T x, Object[] es) {
    Comparable<? super T> key = (Comparable<? super T>) x;
    ...
        if (key.compareTo((T) e) >= 0)
            break;
    ...
}

比如说,我们创建整数队列并添加一些内容:

PriorityQueue<Integer> queue = new PriorityQueue<>();
queue.add(1);

如果我得到通配符的概念,使用<? super T>的唯一效果 <? super T>而不是<T>是编译器扩展compareTo的可能参数类型

public interface Comparable<T> {
    public int compareTo(T o);
}

到任何超类Integer 但我想知道为什么以及如何在这里使用它。 任何一个例子

Comparable<T> key = (Comparable<T>) x;

是不足够的? 或者它是使用“超级”通配符与可比较的指南?

放宽通用签名可以提高代码的灵活性,尤其是在我们讨论参数类型时。 一般准则是规则,但是对于Comparable ,需要这种灵活性的实际例子很少见,因为它们意味着具有在其所有子类型中定义自然顺序的基本类型。

例如,如果您有类似的方法

public static <T extends Comparable<T>> void sort(Collection<T> c) {

}

你不能做以下

List<LocalDate> list = new ArrayList<>();
sort(list); // does not compile

原因是LocalDate实现了ChronoLocalDate ,您可以将ChronoLocalDate所有实现相互比较,换句话说,它们都实现了Comparable<ChronoLocalDate>

因此,方法签名必须是

public static <T extends Comparable<? super T>> void sort(Collection<T> c) {

}

允许实际类型实现Comparable参数Comparable超类型,就像已声明一样。


对于siftUpComparable的特定情况,即没有机会确定实际通用签名的内部Collection方法,它是否使用Comparable<T>Comparable<? super T>无关紧要Comparable<? super T> Comparable<? super T> ,正如它所需要的,是将T的实例传递给compare方法的能力,而即使提供实际的参数也是由另一个未经检查的强制转换完成的。

实际上,由于未选中类型转换,它也可以是Comparable<Object> ,这将消除在compare调用时compare (T)的需要。

但显然,作者并不打算离开实际通用代码所做的太远而使用相同的模式,即使它在这里没有明显的好处。

E可能实际上没有为自己的类暴露出类似的东西。 想象一下这个案例:

class Foo implements Comparable<Foo> { ... }

class Bar extends Foo { ... }

如果您创建PriorityQueue<Bar>的优先级队列,则使用Foo定义的比较方法。 即,你有一个Comparable<? super Bar> Comparable<? super Bar>其中通配符被实现为Foo

仿制药的重点是类型安全。 由于Java泛型在运行时丢失了类型信息,因此我们没有验证此强制转换的方法。 有界通配符是一种在编译时验证类型限制的安全方法,而不是在运行时制作一个hail Mary。

要理解super的不同语义并在泛型中extends ,请参考以下主题:

  相关解决方案