Java 泛型 super/extends - 不同的行为(用于 OCP java 8 学习目的)

Java Generics super/extends - different behaviors (for OCP java 8 study purposes)

假设我有以下结构:

java.lang.Object
class A extends Object { public boolean mA() {return true;} }
class B extends A { public boolean mB() {return false;} }

现在我正在编写一个主要方法来使用它。 我接受以下概念:('Object' 从 super 的 get 方法返回的类型)

public static void m1(List<? super A> l ) {
    l.get(0).toString();
}

因为我可以使用

调用它
m1(new ArrayList<A>());
m1(new ArrayList<Object>());

我也很满意:('A' 从 get 方法返回的扩展类型)

public static void m2(List<? extends A> l ) {
    l.get(0).mA();
}

因为我可以使用

调用它
m2(new ArrayList<A>());
m2(new ArrayList<B>());

最后我的问题是:为什么下面带有 'super' 的定义接收类型 'A' 作为参数,而不是 Object?

Predicate<? extends A> p1 = a -> a.mA(); // ok
Predicate<? super A> p2 = a -> a.mA(); // why is it of type 'A' too??

我认为它会变成类似的东西(我知道下面的代码是无效的......我只是认为它会类似于那个)。

PredicateImpl<T super A> {
    public boolean test(T t);
}

我也检查了反编译的class,但我没有得到任何新的线索。谁能告诉我引擎盖下发生了什么?我已经阅读了 PECS 讨论,但它在这个具体问题上对我没有帮助。

提前致谢! ;)

===== 收到答案后用额外代码编辑=====

Predicate<? super A> pSuper = a -> a.mA();
Predicate<? extends A> pExtends = a -> a.mA();      // ?? A ??

Predicate<Object> pObject = o -> o.equals(null);
Predicate<A> pA = a -> a.mA();
Predicate<B> pB = b -> b.mB();

pSuper = pObject;
pSuper = pA;
pSuper = pB;        // compiler error

pExtends = pObject; // compiler error
pExtends = pA;
pExtends = pB;

有趣的替代语法(尽管我认为 Predicate<? extends Anything> 非常无用,因为它只在测试方法中接受 'null')。不管怎样,我找到了这样的练习,无论如何我都学会了。

Predicate<? extends A> pExtends2 = (B b) -> b.mB();

JLS, Section 9.9讲的是lambda表达式的类型推断。其中一节讨论了存在通配符和边界时的类型推断。

When a generic functional interface is parameterized by wildcards, there are many different instantiations that could satisfy the wildcard and produce different function types. For example, each of Predicate<Integer> (function type Integer -> boolean), Predicate<Number> (function type Number -> boolean), and Predicate<Object> (function type Object -> boolean) is a Predicate<? super Integer>. Sometimes, it is possible to known from the context, such as the parameter types of a lambda expression, which function type is intended (§15.27.3). Other times, it is necessary to pick one; in these circumstances, the bounds are used.

(大胆强调我的)

此处,对于 Predicate<? super A> 的目标类型,lambda 参数 a 的多种可能类型是可能的:ObjectA。目标类型绑定是 ? super A,因此绑定 A 用作类型。

这对于任何通配符边界(上限或下限)都是最有意义的。有了上限,绑定类型就很有意义了。类型为 A 或更低,但它可能只是 A,因此 A 方法应该可用。 Predicate<A> 可分配给 Predicate<? extends A>.

具有下限,类型为 A 或更高。但是为什么不选择Object呢?因为 A 工作正常。

一个Predicate<A>可以分配给一个Predicate<? super A>Predicate<Object> 也可以分配给 Predicate<? super A>,但这会造成不必要的限制。 lambda 表达式将仅限于调用 Object 方法,而它可以像您编写的那样轻松调用 A 方法(方法 mA)。在这里选择限制性最强的类型是有意义的,这样程序员就可以调用最多的方法。此外,根据边界限制最严格的功能接口类型必须是可分配的。 Predicate<A> 可分配给 Predicate<? super A>.

您甚至可以将 lambda 表达式 a -> a.mA() 分配给 Predicate<? extends B>Predicate<? super B> 甚至 Predicate<B>。推断出的类型是B,那个类型肯定有方法mA,继承自A.

如果您尝试将 lambda 表达式 a -> a.mA() 分配给 Predicate<Object>Predicate<?>,则 Object 必须是推断类型。在这里,你会得到关于 mA not being defined on Object.

的编译器错误