Domanda

I have an abstract class UserdataUpdater which extends Updater

Updater has a method declaration

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

Is there anyway to modify this method declaration inside UserdataUpdater to make it more specific, like

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

IUserData extends IAppendOnlyData, because I want classes that extends UserdataUpdater to only take IUserData

È stato utile?

Soluzione

No, you can't. This would break the contract of the superclass, which says: this method accepts a IAppendOnlyData as second argument.

Remember that an instance of a subclass is also an instance of its superclass. So anyone could refer to the subclass instance as its superclass, and call the base method, passing a IAppendOnlyData, without knowing that the instance is actually a subclass instance.

Read more about the Liskov substitution principle.

The only way to do that is to make the superclass generic:

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) {
        ...
    }
}

Altri suggerimenti

You cannot modify a method declaration in a derived class. You can only override a superclass method if the derived class method has the exact same method signature. You must use function overloading and make a new method processRow with the new parameter types you mentioned.

In my experience, you have to use the first declaration, then in the implementation, check to make sure that:

row instanceof IUserData

of course, this is checked at runtime rather than during compile, but I don't know any other way around it. Of course, you can also just cast the row to the type IUserData, whether blindly or after checking its type (above).

Short answer: No.

You can create such a function, but because the signature is different, the compiler will see it as a different function.

If you think about it, what you are trying to do doesn't really make sense. Suppose you wrote a function that takes an Updater as a parameter and calls processRow on it with something that is not IUserData. At compile time, Java has no way to know whether the object passed in an Updater, UserdataUpdater, or some other subclass of Updater. So should it allow the call or not? What should the compiler do?

What you can do is inside UserdataUpdater.processRow, include code that checks the type passed in at runtime and throws an exception or does some other sort of error processing if it is not valid.

Assuming you have no control on the Updater class, you can't do that ... you'll have to implement that method with the exact same signature. However you can check for the type of row, inside your implementation and decide whatever processing is appropriate:

public void processRow (Cluster cluster, IAppendOnlyData row)
{
    if( row instanceof IUserData )
    {
        // your processing here
    }
    else
    {
        // Otherwise do whatever is appropriate.
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top