java 泛型类型:为什么是 Function<?超级 E,? extends F> 比 Function<E, F> 更受欢迎?
java type generic: why Function<? super E, ? extends F> is more preferred than Function<E, F>?
有一个叫做 Foo 的 class 如下:
public class Foo<E> {
private List<E> ls;
public Foo(List<E> ls) {
this.ls = ls;
}
public void add(E l) {
this.ls.add(l);
}
public <F> Foo<F> map(Function<? super E, ? extends F> f) {
Foo<F> res = new Foo<F>(new ArrayList<F>());
for (E l : ls) {
res.add(f.apply(l));
}
return res;
}
}
然后,我从 main 调用:
//Main.java
Foo<Integer> foo1 = new Foo<>(Arrays.asList(1,2,3,4));
Foo<String> foo2 = foo1.map(a -> a.toString());
我想看看将函数定义为 Function<? super E, ? extends F>
与 Function<E,F>
相比有何优势? Function<? super E, ? extends F>
是否具有最大的灵活性?您能否通过更改 Main.java
在示例中显示它?
尝试使用 String 和 Integer 等最终 classes 来推理泛型是个坏主意。
尝试像 A > B > C 这样的层次结构
class A {}
class B extends A {}
class C extends B {}
然后举个例子
Foo<B> foo1 = new Foo<>(new B());
Function<A, C> aToC = a -> new C();
Foo<B> foo2 = foo1.map(aToC);
如果没有 super E
和 extends F
,这将无法工作。该函数采用 A - foo1
是 B,但 A 是 B 的超 class - 并且 returns A C - foo2
期望 B,但 C 扩展B.
如果您的 map
函数被简单地声明为
public <F> Foo<F> map(Function<E, F> f) {
那么上面的代码片段将无法编译。该函数必须是 Function<B, B>
.
希望这能说明为什么更复杂的签名更灵活。
有一个叫做 Foo 的 class 如下:
public class Foo<E> {
private List<E> ls;
public Foo(List<E> ls) {
this.ls = ls;
}
public void add(E l) {
this.ls.add(l);
}
public <F> Foo<F> map(Function<? super E, ? extends F> f) {
Foo<F> res = new Foo<F>(new ArrayList<F>());
for (E l : ls) {
res.add(f.apply(l));
}
return res;
}
}
然后,我从 main 调用:
//Main.java
Foo<Integer> foo1 = new Foo<>(Arrays.asList(1,2,3,4));
Foo<String> foo2 = foo1.map(a -> a.toString());
我想看看将函数定义为 Function<? super E, ? extends F>
与 Function<E,F>
相比有何优势? Function<? super E, ? extends F>
是否具有最大的灵活性?您能否通过更改 Main.java
在示例中显示它?
尝试使用 String 和 Integer 等最终 classes 来推理泛型是个坏主意。
尝试像 A > B > C 这样的层次结构
class A {}
class B extends A {}
class C extends B {}
然后举个例子
Foo<B> foo1 = new Foo<>(new B());
Function<A, C> aToC = a -> new C();
Foo<B> foo2 = foo1.map(aToC);
如果没有 super E
和 extends F
,这将无法工作。该函数采用 A - foo1
是 B,但 A 是 B 的超 class - 并且 returns A C - foo2
期望 B,但 C 扩展B.
如果您的 map
函数被简单地声明为
public <F> Foo<F> map(Function<E, F> f) {
那么上面的代码片段将无法编译。该函数必须是 Function<B, B>
.
希望这能说明为什么更复杂的签名更灵活。