Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 792
Bill Avatar asked Jan 04 '10 15:01

Bill


3 Answers

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.

like image 151
Jon Skeet Avatar answered Nov 13 '22 12:11

Jon Skeet


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:

  1. 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.

  2. 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 method hasCredentials 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 class Derived and give it a method hasCredentials 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.

like image 21
Konrad Rudolph Avatar answered Nov 13 '22 11:11

Konrad Rudolph


"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.

like image 17
Gregory Pakosz Avatar answered Nov 13 '22 10:11

Gregory Pakosz