Java,可以修改抽象类层次结构中超类的方法声明吗?

时间:2012-10-08 20:10:10

标签: java generics abstract-class abstract class-hierarchy

我有一个抽象类UserdataUpdater,它扩展了Updater

Updater有一个方法声明

 public abstract void processRow (Cluster cluster, IAppendOnlyData row);

无论如何都要在UserdataUpdater中修改此方法声明以使其更具体,例如

 public abstract void processRow (Cluster cluster, IUserData row);

IUserData扩展了IAppendOnlyData,因为我希望扩展UserdataUpdater的类只能IUserData

5 个答案:

答案 0 :(得分:13)

不,你不能。这会破坏超类的契约,它表示:此方法接受IAppendOnlyData作为第二个参数。

请记住,子类的实例也是其超类的实例。所以任何人都可以将子类实例称为其超类,并调用基本方法,传递IAppendOnlyData,而不知道该实例实际上是一个子类实例。

详细了解Liskov substitution principle

这样做的唯一方法是使超类具有通用性:

public class Updater<T extends IAppendOnlyData> {
    ...
    public abstract void processRow(Cluster cluster, T row);

}

public class UserdataUpdater extends Updater<IUserData> {
    @Override
    public void processRow(Cluster cluster, IUserData row) {
        ...
    }
}

答案 1 :(得分:1)

您无法修改派生类中的方法声明。如果派生类方法具有完全相同的方法签名,则只能覆盖超类方法。您必须使用函数重载并使用您提到的新参数类型创建新方法processRow

答案 2 :(得分:0)

根据我的经验,你必须使用第一个声明,然后在实现中检查以确保:

row instanceof IUserData

当然,这是在运行时而不是在编译期间检查的,但我不知道其他任何方式。当然,您也可以将行转换为IUserData类型,无论是盲目还是检查其类型(上图)。

答案 3 :(得分:0)

简短回答:不。

您可以创建这样的函数,但由于签名不同,编译器会将其视为不同的函数。

如果你仔细想想,你想要做的事情并没有多大意义。假设您编写了一个函数,该函数将Updater作为参数,并使用非IUserData调用processRow。在编译时,Java无法知道对象是否在Updater,UserdataUpdater或Updater的其他子类中传递。它应该允许通话吗?编译器应该做什么?

您可以在UserdataUpdater.processRow中执行的操作,包括检查在运行时传入的类型的代码,如果无效则抛出异常或进行其他类型的错误处理。

答案 4 :(得分:0)

假设您无法控制Updater类,则无法执行此操作...您必须使用完全相同的签名实现该方法。但是,您可以在实现中检查row的类型,并确定适当的处理:

public void processRow (Cluster cluster, IAppendOnlyData row)
{
    if( row instanceof IUserData )
    {
        // your processing here
    }
    else
    {
        // Otherwise do whatever is appropriate.
    }
}