想象一下,我们有以下课程:
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,并解决了这个问题。
有人能解释一下这段代码中发生了什么吗?
答案 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(在这种情况下我不假设)