Java 通配符默认为 java.lang.Object 而不是上限

Java wildcards defaulted to java.lang.Object instead of upper bound

给定代码

abstract class Base<Thistype extends Base>
{
    public void addOnSomethingListener(Consumer<? super Thistype> action)
    {}

    public void foo()
    {
        System.out.println("foo");
    }
}

class Simple<Thistype extends Simple> extends Base<Thistype>
{

}

class Test1 extends Simple<Test1>
{

}

class Test2 extends Simple
{

}

class Test
{
    public static void main(String[] args)
    {
        Test1 test1 = new Test1();
        Test2 test2 = new Test2();

        test1.addOnSomethingListener(test ->
        {
            test.foo(); // VALID as "test" is of type "Thistype" which is "Test1".
        });

        test2.addOnSomethingListener(test ->
        {
            test.foo(); // INVALID as "test" is of type "Thistype" which is "java.lang.Object" instead of "Base" which is the upper bound.
        });
    }
}

为什么classTest2的泛型类型不是默认为classBase而是默认为classjava.lang.Object

我提供了上限,但如果使用通配符或根本没有给出泛型,这似乎无关紧要。

main函数里面的代码你问我应该可以编译吧

通过声明 Test2 class 而不指定其类型参数:

class Test2 extends Simple {}

您正在创建 raw type。因此编译器将其视为 Object.

的实例

它没有"default to Object"。

实际发生的事情是,通过使用原始类型(Test2 扩展原始类型 Simple),它 "turns off" 该类型的所有泛型。所以 Test2addOnSomethingListener 方法(从原始类型 Simple 继承)实际上具有签名 void addOnSomethingListener(Consumer action) (即参数的类型被擦除为原始类型 Consumer).

碰巧原始类型 Consumeraccept 方法具有签名 void accept(Object)(因为它通常是 void accept(T),但 T in Consumer 是无界的,因此当使用原始类型 Consumer 时,它会被擦除为 void accept(Object).