Java:为什么这个子类有效?

Java:为什么这个子类有效?,java,generics,class,Java,Generics,Class,在这里,我有一个抽象类: abstract class A<E extends A> { abstract void foo(E x); } 这里还有一个(E是B这里是故意的): 什么时候泛型是可选的?我认为A的扩展类(子类)需要指定E 编辑: 到目前为止收到的两个答案都说,如果没有提供参数,E默认为Object 好吧,那么为什么这不起作用呢 D类扩展了{ void foo(对象x){} } 泛型类型参数是可选的。如果使用带有泛型参数但没有这些参数的类,则称为原始类型。因

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

abstract class A<E extends A> {
    abstract void foo(E x);
}
这里还有一个(
E
B
这里是故意的):

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


编辑:

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

好吧,那么为什么这不起作用呢

D类扩展了{
void foo(对象x){}
}

泛型类型参数是可选的。如果使用带有泛型参数但没有这些参数的类,则称为原始类型。因此,您可以使用
A
而不使用泛型参数


请参阅Java泛型常见问题解答。

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

那么,为什么这不起作用(见下文)


您可以使用反射/字节码反编译来检查泛型类型/方法在运行时实际编译为什么

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)
}
import java.lang.reflect.*;
公共静态void列表方法(klazz类){
System.out.println(“用于“+klazz”的声明方法);
对于(方法m:klazz.getDeclaredMethods()){
系统输出打印项次(m);
}       
}
公共静态void main(字符串参数[]){
列表方法(A.class);
//类的声明方法
//摘要A.foo(A)
}

这里有点回避了最初的问题,但是这个声明让我很烦。这并不是说它从根本上是错误的,但它确实在这里提出了泛型用法的问题

abstract class A<E extends A> {
    abstract void foo(E x);
}
抽象类A{
抽象void-foo(ex);
}
在我看来,它就像一个对自身实例执行操作的泛型对象,泛型的唯一可能用途是使父实例可以在编译时自动转换为它的一个子实例。。。使父对象中声明的方法签名在子对象中自动转换为子对象本身的一种方法


也许周一早上我想的太多了

(+1)如果它是可选的,那么将
E
作为默认参数的方法中的参数类型是什么?超类本身?我的意思是这看起来真的很奇怪。它们只是变成了
对象
s,这就是它们在类型擦除中的情况。@cletus:Hm。我怎么能使泛型参数成为非可选的呢?我的意思是,非常奇怪的是,尽管在没有提供参数的情况下默认为
对象
,但在上面的示例中,提供
对象
作为参数实际上并不起作用@增量—您不能强制它。您需要了解Java泛型是如何工作的:它们只是用于转换
Object
s的语法糖。它们(大部分)不会在运行时保留。在这种情况下,它实际上会变成
A
。(注意:对类名的泛型参数使用命名标准无助于澄清!)有趣(+1)。所以我不能将泛型参数设置为非可选?关于编辑:如果您提供泛型类型参数,它们将被强制执行。在JDK7
javac
中,您可以为此打开一个警告,IIRC
-Xlint:rawtypes
@Tom-Nice。我得调查一下。好吧,现在说得通了——谢谢。但我只是不明白类型擦除是如何导致这些类在编译后成为对象的(正如其他答案所建议的那样)——它们不会变成A吗?你能重新表述一下吗?我真的不确定你所说的“泛型的唯一可能的用法是(如果是什么?),这样父实例可以自动转换到编译时决定的它的一个子实例”是什么意思。。。我想我昨天需要我的咖啡!!!基本上,我只是觉得很奇怪,模板类只接受自身或其后代作为类型参数。我想知道为什么会有人想要这样的类结构,这有什么可能的用途。然而,我确实意识到,这段代码完全是为了演示其他的东西,所以很可能这从来就不是我的意图。是的,如果这就是我所做的事情的重点,我可能会一起避免泛型并这样做:
abstract class A{abstract void foo(ae);}
,这也是我的第一本能。但是,在某些情况下,您希望子级重写父级功能,同时将返回的类型保留为子级类型而不是泛型父级类型。我想知道这样做是否会允许我们在不违反Liskov替换原则的情况下重写返回类型
class D extends A{
    void foo(A x){}
}
class D extends A<Object>{
    void foo(Object x){}
}
class D extends A<Object>{
    void foo(Object x){}
}
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)
}
abstract class A<E extends A> {
    abstract void foo(E x);
}