【发布时间】:2017-02-17 03:08:46
【问题描述】:
我有两个课,
A.java
public abstract class A {
@Override
public abstract <T extends A> T add();
@Override
public abstract <T extends A> T addWithParam(T param);
}
B.java
public class B extends A {
@Override
public B add() {...}
@Override
public B addWithParam(B param) {...}
}
add() 方法编译,但addWithParam 产生错误,说 addWithParam(B) 必须覆盖更高类之一中的方法(在这种情况下为 A)。一个修复方法是完全丢失覆盖注释,但我的意图是强制用户覆盖 B 类中的方法并返回 B 类型的对象。
我只能想出两种方法来解决这个问题。第一个解决方案是将返回类型从泛型类型T 设置为A。这将允许我返回类型 A,但是用户必须将返回结果从 B.addWithParam(B) 转换为类型 B,这是我试图避免的。
另一个解决方案是将抽象方法的可见性从公共更改为受保护(在A.java 中)。在前面提到的解决方案中,我将返回类型更改为A,A 的继承类创建了一个返回(B) B.addWithParam(B param) 的方法(请记住B.addWithParam(B param) 返回类型为A,由超类指定)。
那么这里的问题是,为什么会产生原来的错误呢?我只是写错了代码,还是 Java 直接不支持我想要实现的目标?
【问题讨论】:
-
编译器出错的直接原因是在抽象类中,在运行时,
addWithParam()方法将Object作为输入,同时也返回了Object。在您的覆盖版本中(实际上并没有真正覆盖),您将具体的B类型作为输入,然后还返回B类型。 -
@TimBiegeleisen:反例:考虑
A声明为class A<T>,方法为T addWithParam(T param),B声明为class B extends A<B>和B' saddWithParam是B addWithParam(B param)。您的前提也适用于这种情况——在运行时,A的addWithParam采用Object并返回Object,而在覆盖版本中,它采用B并返回B- - 所以根据你的逻辑,它应该是无效的。然而,这种情况是完全有效的,并且可以正确覆盖。