1

我有一个UserdataUpdater扩展的抽象类Updater

Updater有一个方法声明

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

有没有办法在里面修改这个方法声明UserdataUpdater,使它更具体,比如

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

IUserDataextends IAppendOnlyData,因为我想要扩展的类UserdataUpdater只接受IUserData

4

5 回答 5

13

不,你不能。这将打破超类的约定,即:此方法接受 IAppendOnlyData 作为第二个参数。

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

阅读有关Liskov 替换原则的更多信息。

做到这一点的唯一方法是使超类泛型:

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) {
        ...
    }
}
于 2012-10-08T20:15:16.907 回答
1

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

于 2012-10-08T20:15:24.677 回答
0

假设您无法控制 Updater 类,则不能这样做……您必须使用完全相同的签名来实现该方法。但是,您可以在您的实现中检查 , 的类型row并决定适当的处理:

public void processRow (Cluster cluster, IAppendOnlyData row)
{
    if( row instanceof IUserData )
    {
        // your processing here
    }
    else
    {
        // Otherwise do whatever is appropriate.
    }
}
于 2012-10-08T20:19:54.047 回答
0

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

row instanceof IUserData

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

于 2012-10-08T20:15:44.990 回答
0

简短的回答:没有。

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

如果您考虑一下,您正在尝试做的事情并没有真正的意义。假设您编写了一个函数,该函数将 Updater 作为参数并使用不是 IUserData 的内容对其调用 processRow。在编译时,Java 无法知道对象是在 Updater、UserdataUpdater 还是 Updater 的其他子类中传递的。那么它是否应该允许通话?编译器应该做什么?

您可以在 UserdataUpdater.processRow 中包含检查在运行时传入的类型并抛出异常或在其无效时进行其他类型的错误处理的代码。

于 2012-10-08T20:17:00.493 回答