简体   繁体   English

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

[英]Lower bounded wildcard (Comparable<? super K>)

In collections casting to Comparable interface is often used, eg. 在集合中,经常使用Comparable接口,例如。 in PriorityQueue : 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;
    ...
}

Say, we create queue of integers and add something: 比如说,我们创建整数队列并添加一些内容:

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

If I get the concept of wildcards right, the only effect of using <? super T> 如果我得到通配符的概念,使用<? super T>的唯一效果 <? super T> instead of <T> is that compiler extends the possible argument type of compareTo <? super T>而不是<T>是编译器扩展compareTo的可能参数类型

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

to any superclass of Integer . 到任何超类Integer But I'm wondering why and how it can be used here. 但我想知道为什么以及如何在这里使用它。 Any example where 任何一个例子

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

is not enough? 是不足够的? Or it's kind of guideline to use "super" wildcard with Comparable? 或者它是使用“超级”通配符与可比较的指南?

Relaxing the generic signature can raise the flexibility of code, especially when we're talking about parameter types. 放宽通用签名可以提高代码的灵活性,尤其是在我们讨论参数类型时。 The general guideline is the PECS rule, but for Comparable , practical examples of needing this flexibility are rare, as these imply having a base type defining a natural order among all of its subtypes. 一般准则是PECS规则,但是对于Comparable ,需要这种灵活性的实际例子很少见,因为它们意味着具有在其所有子类型中定义自然顺序的基本类型。

Eg, if you have a method like 例如,如果您有类似的方法

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

}

you can not do tho following 你不能做以下

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

The reason is that LocalDate implements ChronoLocalDate and you can compare all implementations of ChronoLocalDate with each other, in other words, they all implement Comparable<ChronoLocalDate> . 原因是LocalDate实现了ChronoLocalDate ,您可以将ChronoLocalDate所有实现相互比较,换句话说,它们都实现了Comparable<ChronoLocalDate>

So, the method signature has to be 因此,方法签名必须是

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

}

to allow actual types to implement Comparable parameterized with a super type, just like Collections.sort has been declared. 允许实际类型实现Comparable参数Comparable超类型,就像已声明Collections.sort一样。


For the specific case of siftUpComparable , ie an internal Collection method which has no chance to determine the actual generic signature, it indeed doesn't matter whether it uses Comparable<T> or Comparable<? super T> 对于siftUpComparable的特定情况,即没有机会确定实际通用签名的内部Collection方法,它是否使用Comparable<T>Comparable<? super T>无关紧要Comparable<? super T> Comparable<? super T> , as all it needs, is the ability to pass an instance of T to the compare method, whereas even providing the actual argument is done by another unchecked cast anyway. Comparable<? super T> ,正如它所需要的,是将T的实例传递给compare方法的能力,而即使提供实际的参数也是由另一个未经检查的强制转换完成的。

In fact, since the type cast is unchecked , it could have been a cast to Comparable<Object> as well, which would eliminate the need to do the (T) cast at the compare invocation. 实际上,由于未选中类型转换,它也可以是Comparable<Object> ,这将消除在compare调用时compare (T)的需要。

But obviously, the author did not intend to move too far away from what actual generic code would do and used the same pattern, even if it does not have an obvious benefit here. 但显然,作者并不打算离开实际通用代码所做的太远而使用相同的模式,即使它在这里没有明显的好处。

E might not actually expose a comparable for its own class. E可能实际上没有为自己的类暴露出类似的东西。 Imagine this case: 想象一下这个案例:

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

class Bar extends Foo { ... }

If you make a priority queue of PriorityQueue<Bar> , then you use the comparison method defined in Foo . 如果您创建PriorityQueue<Bar>的优先级队列,则使用Foo定义的比较方法。 ie, you have a Comparable<? super Bar> 即,你有一个Comparable<? super Bar> Comparable<? super Bar> where the wildcard is realized as Foo Comparable<? super Bar>其中通配符被实现为Foo

The whole point of generics is being type safe. 仿制药的重点是类型安全。 Since Java generics lose type information at runtime, we don't have a method of validating this cast. 由于Java泛型在运行时丢失了类型信息,因此我们没有验证此强制转换的方法。 Bounded wildcards are a safe way of validating a type restriction at compile time, rather than making a hail Mary cast at runtime. 有界通配符是一种在编译时验证类型限制的安全方法,而不是在运行时制作一个hail Mary。

To understand the different semantics of super and extends in generics, consult this thread: 要理解super的不同语义并在泛型中extends ,请参考以下主题:
What is PECS (Producer Extends Consumer Super)? 什么是PECS(制作人扩展消费者超级)?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM