Java:为什么这个Subclass有效?

时间:2010-03-29 02:07:03

标签: java generics class

在这里,我有一个抽象类:

abstract class A<E extends A> {
    abstract void foo(E x);
}

这是一个扩展A的类:

class B extends A<B>{
    void foo(B x){}
}

这是另一个(E B是故意的):

class C extends A<B>{
    void foo(B x){}
}

这两个类都是有效的,并且这对我来说是有道理的。

然而令我困惑的是这可能是有效的:

class D extends A{
    void foo(A x){}
}

因为泛型是什么时候可选的?我认为A的扩展类(子类)需要指定E


修改

到目前为止收到的两个答案都说如果没有提供参数,E默认为一个Object。

好吧 - 那么为什么这不起作用(下图)?

class D extends A<Object>{
    void foo(Object x){}
}

4 个答案:

答案 0 :(得分:3)

通用类型参数是可选的。如果使用带有泛型参数的类而没有这些参数,则称为原始类型。所以是的,你可以使用没有通用参数的A

请参阅Java Generics FAQ中的Raw Types

答案 1 :(得分:3)

添加泛型时,Java希望保持与先前版本的向后兼容性。因此,泛型是可选的选项,并且通用信息在编译时使用,但在运行时完全删除(称为类型擦除)。

答案 2 :(得分:1)

  

那么为什么这不起作用(下面)?

class D extends A<Object>{
    void foo(Object x){}
}

因为您定义了class A<E extends A>;您已将发言权提高到A而不是Object。这很好用:

class D extends A<A>{
   void foo(A x){}
}

您可以使用反射/字节码反编译来检查通用类型/方法在运行时实际编译的内容。

import java.lang.reflect.*;

public static void listMethods(Class<?> klazz) {
    System.out.println("Declared methods for " + klazz);
    for (Method m : klazz.getDeclaredMethods()) {
        System.out.println(m);
    }       
}
public static void main(String args[]) {
    listMethods(A.class);
    // Declared methods for class A
    // abstract void A.foo(A)
}

答案 3 :(得分:0)

在这里略微偏离原来的问题,但这个宣言让我感到困惑。并不是说它从根本上是错误的,但它确实在这里提出了关于泛型的使用的问题。

abstract class A<E extends A> {
    abstract void foo(E x);
}

对我来说就像是一个对自身实例进行操作的通用对象,唯一可能使用泛型的方式是父实例可以自动转换为其中一个在编译时确定的子进程...将子对象中自动转换的父方法签名在子对象中声明...

也许我只想在星期一早上做太多考虑!!