2017-05-24 43 views
2

鉴于为什么泛型类型Test2类不默认为Base类,而是默认为java.lang.Object类的代码Java的通配符默认为java.lang.Object继承,而不是上限

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. 
     }); 
    } 
} 

我提供了上限,但似乎这是不相关的,如果使用通配符或根本没有泛型。

如果你问我,主函数中的代码应该能够被编译。

回答

4

通过声明Test2类没有specyfing其类型参数:

class Test2 extends Simple {} 

要创建一个raw type。因此,编译器将其视为Object的一个实例。

+0

好的,但有什么方法可以将它默认为上限......就好像我没有错,它永远不会是其他任何东西,这也可以解决我的问题 – Wietlol

+0

您可以添加另一个类:class UpperBounded扩展Simple {}'和使用它作为类型参数的'Test2'声明:'class Test2 extends Simple {}'。 – syntagma

+0

是的,但与Test1类相比没有区别。 – Wietlol

0

它不会“默认为Object”。

实际发生的情况是,通过使用原始类型(Test2扩展原始类型Simple),它会“关闭”该类型的所有泛型。因此,Test2addOnSomethingListener方法(其从原始类型Simple继承)实际上具有签名void addOnSomethingListener(Consumer action)(即参数的类型被擦除为原始类型Consumer)。

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

相关问题