什么是通用<?的真实例子?超级T>?

Ban*_*kyo 74 java generics inheritance super

据我所知,它<? super T>代表任何超级类T(T任何级别的父类).但我真的很难想象这个通用绑定通配符的任何现实生活示例.

我明白了什么<? super T>意思,我看过这个方法:

public class Collections {
  public static <T> void copy(List<? super T> dest, List<? extends T> src) {
      for (int i = 0; i < src.size(); i++)
        dest.set(i, src.get(i));
  }
}
Run Code Online (Sandbox Code Playgroud)

我正在寻找一个真实生活用例的例子,可以使用这种结构,而不是解释它是什么.

Eug*_*ene 46

我能想到的最简单的例子是:

public static <T extends Comparable<? super T>> void sort(List<T> list) {
    list.sort(null);
}
Run Code Online (Sandbox Code Playgroud)

取自同样的Collections.这种方式Dog可以实现Comparable<Animal>,如果Animal已经实现了,Dog则无需执行任何操作.

编辑一个真实的例子:

经过一些电子邮件的ping-pongs,我被允许在我的工作场所展示一个真实的例子(耶!).

我们有一个名为Sink(它无关紧要)的界面,这个想法就是积累东西.声明非常简单(简化):

interface Sink<T> {
    void accumulate(T t);
}
Run Code Online (Sandbox Code Playgroud)

显然有一个辅助方法可以将List它的元素排放到一个Sink(它有点复杂,但要简化它):

public static <T> void drainToSink(List<T> collection, Sink<T> sink) {
    collection.forEach(sink::accumulate);
}
Run Code Online (Sandbox Code Playgroud)

这很简单吧?好...

我可以有一个List<String>,但我想把它排到一个Sink<Object>- 这对我们来说是相当普遍的事情; 但这会失败:

Sink<Object> sink = null;
List<String> strings = List.of("abc");
drainToSink(strings, sink);
Run Code Online (Sandbox Code Playgroud)

为此,我们需要将声明更改为:

public static <T> void drainToSink(List<T> collection, Sink<? super T> sink) {
    ....
}
Run Code Online (Sandbox Code Playgroud)

  • 当然你可以通过制作列表以相反的方式定义它吗?延伸T? (2认同)

Ben*_*oit 15

假设你有这个类层次结构:Cat继承自Mammal,而Mammal继承自Animal.

List<Animal> animals = new ArrayList<>();
List<Mammal> mammals = new ArrayList<>();
List<Cat> cats = ...
Run Code Online (Sandbox Code Playgroud)

这些调用有效:

Collections.copy(animals, mammals); // all mammals are animals
Collections.copy(mammals, cats);    // all cats are mammals
Collections.copy(animals, cats);    // all cats are animals
Collections.copy(cats, cats);       // all cats are cats 
Run Code Online (Sandbox Code Playgroud)

但是,这些电话是不是有效的:

Collections.copy(mammals, animals); // not all animals are mammals
Collections.copy(cats, mammals);    // not all mammals are cats
Collections.copy(cats, animals);    // mot all animals are cats
Run Code Online (Sandbox Code Playgroud)

因此,方法签名只是确保您从更具体(在继承层次结构中更低)类复制到更通用的类(继承层次结构中的上层),而不是相反.

  • 但是,不需要`super` 关键字来使其工作。此签名也将暴露相同的行为:`public static &lt;T&gt; void copy(List&lt;T&gt; dest, List&lt;? extends T&gt; src) {` (2认同)

Ole*_*hov 6

例如,查看Collections.addAll方法implmenetation:

public static <T> boolean addAll(Collection<? super T> c, T... elements) {
    boolean result = false;
    for (T element : elements)
        result |= c.add(element);
    return result;
}
Run Code Online (Sandbox Code Playgroud)

这里,元素可以插入到元素类型是元素类型的超类型的任何集合中T.

没有下限的通配符:

public static <T> boolean addAll(Collection<T> c, T... elements) { ... }
Run Code Online (Sandbox Code Playgroud)

以下内容无效:

List<Number> nums = new ArrayList<>();
Collections.<Integer>addAll(nums , 1, 2, 3);
Run Code Online (Sandbox Code Playgroud)

因为这个词Collection<T>比限制更严格Collection<? super T>.


另一个例子:

Predicate<T>Java中的接口,它<? super T>在以下方法中使用通配符:

default Predicate<T> and(Predicate<? super T> other);

default Predicate<T>  or(Predicate<? super T> other);
Run Code Online (Sandbox Code Playgroud)

<? super T> 允许链接更广泛的不同谓词,例如:

Predicate<String> p1 = s -> s.equals("P");
Predicate<Object> p2 = o -> o.equals("P");

p1.and(p2).test("P"); // which wouldn't be possible with a Predicate<T> as a parameter
Run Code Online (Sandbox Code Playgroud)