Pau*_*oek 6 java generics inheritance type-erasure
假设我有以下结构:
public interface A {
}
public interface B {
}
public interface B1 extends B {
}
public interface B2 extends B {
}
public class C implements A, B1 {
private final String s;
public C(final String s) {
this.s = s;
}
}
public class D implements A, B2 {
private final Exception e;
public D(final Exception e) {
this.e = e;
}
}
public class SomeClass<T> {
private final T t;
private final Exception e;
public SomeClass(final T t, final Exception e) {
this.t = t;
this.e = e;
}
public <U extends B> U transform(final java.util.function.Function<T, ? extends U> mapper1, final java.util.function.Function<Exception, ? extends U> mapper2) {
return t == null ? mapper2.apply(e) : mapper1.apply(t);
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们在另一个类中执行以下操作:
public class AnotherClass {
public static void main(final String[] args) {
SomeClass<String> someClass = new SomeClass<>("Hello World!", null);
// this line is what is bothering me
A mappedResult = someClass.transform(C::new, D::new);
}
}
Run Code Online (Sandbox Code Playgroud)
代码编译没有任何问题。为什么要编译代码?即使方法中的泛型 U 被声明为 B 的子类型,“mappedResult”的类型怎么可能是 A?
好吧,根据对这个问题的评论以及与其他人的一些讨论,我错过了一个可能需要解决的要点,这实际上解释了评论中给出的答案。
很明显,以下内容可以编译:
Object mappedResult = someClass.transform(C::new, D::new);
Run Code Online (Sandbox Code Playgroud)
当然,Object 并不是 B 的子类。绑定将确保 C 和 D 的类型(在本例中)将是 B 的子类型,但由于 C 和 D 实现的其他接口,它们也可以是其他类型。编译器将检查它们是什么类型,并查看它们共有的最具体的类型。在本例中,既是 A 又是 B,因此类型被派生为 A & B。因此,将此结果分配给 A 是可能的,因为编译器也会将结果派生为 A。
界限确实提供了一些有关输入的限制,但不涉及输出,也不涉及可将结果分配给的变量类型。这也是我之前很困惑的地方。
另一种查看方法如下:如果该方法定义如下:
public <U> U transform(final java.util.function.Function<T, ? extends U> mapper1, final java.util.function.Function<Exception, ? extends U> mapper2) {
return t == null ? mapper2.apply(e) : mapper1.apply(t);
}
Run Code Online (Sandbox Code Playgroud)
那么调用时仍然可以将结果赋值给 A 或 B。界限对此没有影响。它在这里确保的是两个映射器函数都需要映射到 U 子类型的结果。通过绑定,它成为 U 的子类型,而 U 是 B 的子类型。但事实是结果是 A 的子类型不会改变它也是 B 的子类型的事实。因此,结果可以分配给任一类型。
归档时间: |
|
查看次数: |
98 次 |
最近记录: |