Java:泛型继承混淆

时间:2010-10-15 12:44:34

标签: java oop generics inheritance override

想象一下,我们有以下课程:

public interface MyInterface<T> {
    List<T> getList(T t);
}

abstract class BaseClass<T extends Number> implements MyInterface<T> {
    @Override
    public List<T> getList(Number t) {
        return null;
    }
}

class ChildClass extends BaseClass<Integer> {
    @Override
    public List<Integer> getList(Integer t) {
        return super.getList(t);  //this doesn't compile
    }
}
getList中的

ChildClass无法编译,输出为:

abstract method getList(T) in com.mypackage.MyInterface cannot be accessed directly

我无法理解为什么在ChildClass中没有覆盖BaseClass.getList方法。

但令我完全困惑的是使其编译的修复:

class ChildClass extends BaseClass<Integer> {
    @Override
    public List<Integer> getList(Integer t) {
        return super.getList((Number) t);  //Now it compiles!
    }
}

所以我将Integer转换为Number,并解决了这个问题。

有人能解释一下这段代码中发生了什么吗?

5 个答案:

答案 0 :(得分:5)

您的基类应如下所示:

abstract class BaseClass<T extends Number> implements MyInterface<T> {
    @Override
    public List<T> getList(T t) {
        return null;
    }
}

您没有使用T,而是使用Number类作为参数。

答案 1 :(得分:2)

它不会覆盖,因为抽象方法将Number作为参数,具体方法采用Integer。它们必须相同才能覆盖。

您应该更改抽象类实现,将类型T作为参数。

答案 2 :(得分:2)

为什么不将超类方法定义为

public List<T> getList(T t)

答案 3 :(得分:1)

想象中的课程发生了什么。

 abstract class BaseClass<T extends Number> implements MyInterface<T> {
    @Override
    public List<T> getList(Number t) {
        return null;
    }
}

这个类有一个通用参数(T),它必须扩展Number类并实现接口MyInterface

您还尝试覆盖不存在的方法,因为此类不会扩展其他任何类。当一个类正在实现一个接口时,不需要覆盖接口方法,因为它只是描述。

如果我们删除@override注释会发生什么。

 abstract class BaseClass<T extends Number> implements MyInterface<T> {

    public List<T> getList(Number t) {
        return null;
    }
}

在这种情况下我们从接口实现该方法但是创建一个新方法,这个方法参数是与T相同类型的Number,它可能会导致类有一些错误两个相同的方法。 (未经编译器测试)

此方法的实现应该如下所示

 abstract class BaseClass<T extends Number> implements MyInterface<T> {

    public List<T> getList(T t) { //Because T is allready restricted to be Number
        return null;
    }
}

当您指定类型时覆盖它时调用此方法没有问题

class ChildClass extends BaseClass<Integer> {
    @Override
    public List<Integer> getList(Integer t) {
        return super.getList(t); 
    }
}

事先你不必为了返回null而实现它,然后在某个子类中覆盖它。你能做的就是像这样创建类

 abstract class BaseClass<T extends Number> implements MyInterface<T> {

    private List<T> list = new ArrayList<T>(); //The way of initialization is up to You

    public List<T> getList() { //Because T is allready restricted to be Number
        return list;
    }

}

答案 4 :(得分:0)

正如其他同事所指出的那样,问题的原因是父方法的签名不正确。铸造工作的原因在于编译器如何处理泛型。它保证如果您使用泛型,则不会出现运行时ClassCastException问题,但仅当您不进行强制转换时。一旦你这样做,你实际上说编译器会关闭,因为你更清楚你的类型是什么。但是在此之后你可能会在运行时得到ClassCastException(在这种情况下我不假设)