Overriding private methods in Java
As succinctly described here, overriding private methods in Java is invalid because a parent class's private methods are "automatically final, and hidden from the derived class". My question is largely academic.
How is it not a violation of encapsulation to not allow a parent's private method to be "overridden" (ie, implemented independently, with the same signature, in a child class)? A parent's private method cannot be accessed or inherited by a child class, in line with principles of encapsulation. It is hidden.
So, why should the child class be restricted from implementing its own method with the same name/signature? Is there a good theoretical foundation for this, or is this just a pragmatic solution of some sort? Do other languages (C++ or C#) have different rules on this?
You can't override a private method, but you can introduce one in a derived class without a problem. This compiles fine:
class Base
{
private void foo()
{
}
}
class Child extends Base
{
private void foo()
{
}
}
Note that if you try to apply the @Override
annotation to Child.foo()
you'll get a compile-time error. So long as you have your compiler/IDE set to give you warnings or errors if you're missing an @Override
annotation, all should be well. Admittedly I prefer the C# approach of override
being a keyword, but it was obviously too late to do that in Java.
As for C#'s handling of "overriding" a private method - a private method can't be virtual in the first place, but you can certainly introduce a new private method with the same name as a private method in the base class.
Well, allowing private methods to be overwritten will either cause a leak of encapsulation or a security risk. If we assume that it were possible, then we’d get the following situation:
-
Let's say that there's a private method
boolean hasCredentials()
then an extended class could simply override it like this:boolean hasCredentials() { return true; }
thus breaking the security check.
-
The only way for the original class to prevent this would be to declare its method
final
. But now, this is leaks implementation information through the encapsulation, because a derived class now cannot create a methodhasCredentials
any more – it would clash with the one defined in the base class.That’s bad: lets say this method doesn’t exist at first in
Base
. Now, an implementor can legitimately derive a classDerived
and give it a methodhasCredentials
which works as expected.But now, a new version of the original
Base
class is released. Its public interface doesn’t change (and neither do its invariants) so we must expect that it doesn’t break existing code. Only it does, because now there’s a name clash with a method in a derived class.
I think the question stems from a misunderstanding:
How is it /not/ a violation of encapsulation to not allow a parent's private method to be "overridden" (ie, implemented independently, with the same signature, in a child class)
The text inside the parentheses is the opposite of the text before it. Java does allow you to “independently implement [a private method], with the same signature, in a child class”. Not allowing this would violate encapsulation, as I’ve explained above.
But “to not allow a parent's private method to be "overridden"” is something different, and necessary to ensure encapsulation.
"Do other languages (C++ or C#) have different rules on this?"
Well, C++ has different rules: the static or dynamic member function binding process and the access privileges enforcements are orthogonal.
Giving a member function the private
access privilege modifier means that this function can only be called by its declaring class, not by others (not even the derived classes). When you declare a private
member function as virtual
, even pure virtual (virtual void foo() = 0;
), you allow the base class to benefit from specialization while still enforcing the access privileges.
When it comes to virtual
member functions, access privileges tells you what you are supposed to do:
-
private virtual
means that you are allowed to specialize the behavior but the invocation of the member function is made by the base class, surely in a controlled fashion -
protected virtual
means that you should / must invoke the upper class version of the member function when overriding it
So, in C++, access privilege and virtualness are independent of each other. Determining whether the function is to be statically or dynamically bound is the last step in resolving a function call.
Finally, the Template Method design pattern should be preferred over public virtual
member functions.
Reference: Conversations: Virtually Yours
The article gives a practical use of a private virtual
member function.
ISO/IEC 14882-2003 §3.4.1
Name lookup may associate more than one declaration with a name if it finds the name to be a function name; the declarations are said to form a set of overloaded functions (13.1). Overload resolution (13.3) takes place after name lookup has succeeded. The access rules (clause 11) are considered only once name lookup and function overload resolution (if applicable) have succeeded. Only after name lookup, function overload resolution (if applicable) and access checking have succeeded are the attributes introduced by the name’s declaration used further in expression processing (clause 5).
ISO/IEC 14882-2003 §5.2.2
The function called in a member function call is normally selected according to the static type of the object expression (clause 10), but if that function isvirtualand is not specified using aqualified-idthen the function actually called will be the final overrider (10.3) of the selected function in the dynamic type of the object expression [Note: the dynamic type is the type of the object pointed or referred to by the current value of the object expression.