Java 为什么该代码涉及“引用”;?超级T";编译成功?

Java 为什么该代码涉及“引用”;?超级T";编译成功?,java,Java,我正在努力理解?super T来了解它是如何工作的,我被下面的示例卡住了: class Thing { AnotherThing change() { return null; } } class AnotherThing {} interface Fn<A, B> { B run(A a); } class Stream<T> { <R> Stream<R> map(Fn<? super T, ? extends R>

我正在努力理解
?super T
来了解它是如何工作的,我被下面的示例卡住了:

class Thing {
  AnotherThing change() { return null; }
}

class AnotherThing {}

interface Fn<A, B> {
  B run(A a);
}

class Stream<T> {
  <R> Stream<R> map(Fn<? super T, ? extends R> fn) {
     return null;
  }
}

void method() {
  Stream<Thing> s = new Stream<>();
  s.map(a -> a.change());
}
类的东西{
另一个更改(){return null;}
}
类另一个{}
接口Fn{
B运行(A);
}
类流{
河流图(Fn)
但事实并非如此

但事实并非如此。从
Fn开始,我们来讨论
java.util.function.Consumer
,而不是使用自定义的
Fn
接口。如果您不知道,
Consumer
接口有一个抽象方法:
accept(T)
。当您使用
Consumer而不是使用自定义
Fn
接口时,让我们谈谈
java.util.function.Consumer
。如果您不知道,
Consumer
接口有一个抽象方法:
accept(T)
。当你使用
ConsumerVery时,回答得很好。感谢你花时间。我从中学到了很多……这是我大脑能够处理的部分。谢谢你,特别是最后一个例子(这足以帮助我理解).现在我明白了。类型已经确定为
T
。但是
T
也可以是
Object
。因此,允许
Fn
更一般、更好(取决于我们想要什么)。我可以理解为什么Java将
a
推断为
T
。这是因为类型实际上是
T
,并且它是最具包容性的(例如,支持最多的方法).这很有道理。回答得很好。谢谢你花时间。我从中学到了很多…这部分我的大脑可以处理。谢谢你,特别是最后一个例子(这足以帮助我理解).现在我明白了。类型已经确定为
T
。但是
T
也可以是
Object
。因此,允许
Fn
更一般、更好(取决于我们想要什么)。我可以理解为什么Java将
a
推断为
T
。这是因为类型实际上是
T
,并且它是最包容的(例如,支持最多的方法)。这是有道理的。
Consumer<? super CharSequence> con = System.out::println;
con.accept("Some string"); // String implements CharSequence
con.accept(new Object()); // compilation error
void subscribe(Consumer<? super CharSequence> con) { ... }
Consumer<Object> con = System.out::println;
subscribe(con);
Fn<Thing, AnotherThing> f = a -> a.change(); // or you can use Thing::change
Stream<Thing> stream = new Stream<>();
stream.map(f);
Fn<Object, AnotherThing> f = a -> a.change();
Stream<Thing> stream = new Stream<>();
stream.map(f);