gpt4 book ai didi

java - 为什么这段涉及 "? super T"的代码可以编译成功?

转载 作者:行者123 更新时间:2023-12-02 01:31:40 25 4
gpt4 key购买 nike

我试图理解? 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());
}

最奇怪的一点是Java可以推断出aThing因此,可以调用change() .

但事实并非如此。来自 Fn<? super T, ? extends R> fn , a可能是Thingjava.lang.Object ;两者都是T的“ super ” (或者,在本例中为 Thing )。

我错过了一些关于 ? super T 的类(class)。我想知道是否有人可以解释为什么 Java 可以推断出 aThing 。谢谢!

最佳答案

而不是使用自定义 Fn界面,我们来说说java.util.function.Consumer<T> 。如果您不知道,Consumer接口(interface)有一个抽象方法:accept(T) 。当您使用Consumer<? super T>时你是说 Consumer实现可以接受T T 的父类(super class)型。然而,这并不意味着 T 的任何父类(super class)型可以传给accept方法——它的类型必须是 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);

这使得 API 具有灵 active 。调用者可以传递Consumer旨在接受T (即 CharSequence )或 T 的父类(super class)型(例如 Object )。但实际类型传递给 accept方法仍然是T (即 CharSequence ),它只是 Consumer实现可以更笼统一些。如果 subscribe 参数,上面的方法将不起作用被宣布Consumer<CharSequence>相反。

一个Consumer毫不奇怪,他是一名消费者。当某些东西可以生产时,通常最好使用 ? extends而不是? super 。这称为“生产者扩展消费者 super ”(PECS)。您可以在this question中阅读更多相关信息。 .

回到您的示例,您有一个名为 Stream<T> 的类使用方法Stream<R> map(Fn<? super T, ? extends R>)你问它怎么知道 TThing 。它知道这一点,因为您已经声明了 Stream<Thing>这使得 T一个Thing 。当您调用 map您正在实现的方法Fn排队。这使得实现使用 Thing对于 T并且,根据 lambda 内的返回签名,使用 AnotherThing对于 R 。换句话说,您的代码相当于:

Fn<Thing, AnotherThing> f = a -> a.change(); // or you can use Thing::change
Stream<Thing> stream = new Stream<>();
stream.map(f);

但是您可以传递 Fn<Object, AnotherThing>map方法。但请注意,使用时:

Fn<Object, AnotherThing> f = a -> a.change();
Stream<Thing> stream = new Stream<>();
stream.map(f);

a声明类型现在将是 Object实际类型仍然是 Thing (即 T )。

关于java - 为什么这段涉及 "? super T"的代码可以编译成功?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55962598/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com