views:

744

answers:

8

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?

+17  A: 

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.

Jon Skeet
As I understand this, you'll only get an error if you insist on putting an `@override` annotation on the method in your child class.
Carl Smotricz
(+1), though I don't fancy the curly-bracket-on-new-line
Bozho
@Carl: Yes, I was just editing to say that you'll get an error if you *do* try to claim it's overriding a method when it's not.
Jon Skeet
your answer reminds me the answers of http://stackoverflow.com/questions/1953530/why-does-java-prohibit-static-fields-in-inner-classes/1953580#1953580 -- most answers just assert the facts "no you can't" and explain what you can do to workaround these facts, but they don't really try to answer the question "why it's decided like this?"
Gregory Pakosz
@Gregory: I don't see why. In this case I'm correcting the OP's misunderstanding - he thought you couldn't do something which in fact you can, which means there's no "why" to answer.
Jon Skeet
Exactly; this clearly isn't a workaround. The OP's assumption is incorrect, as he's conflating the concept of overriding with the keyword. You can do the former, but the latter is invalid (as far as the subclass knows, there is no method to override).
Robert Grant
@Jon: my bad, I interpreted the question as "why can't you override private methods?"
Gregory Pakosz
Thanks Jon. Your answer is very helpful and made me reconsider the cause of my issue. I was wrongly assuming the cause of my issue. I think my issue has to do with the way I was setting up my constructor. I will add detail to the main thread.
Bill
@Jon: I have added clarification in light of all comments here:http://stackoverflow.com/questions/2000137/overriding-private-methods-in-java/2002872#2002872
Bill
+3  A: 

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.

Konrad Rudolph
Are you saying that John Skeet's answer is incorrect?
rsp
@rsp: no. Jon’s and my answers are not in disagreement, on the contrary.
Konrad Rudolph
Ok, I misread your points 1. and 2. At first glance it wasn't clear to me you were describing a hypothetical situation.
rsp
@Konrad: That helps a lot to shed some light on the "why". However, for item 1., could this not be addressed by looking at the type of the object calling the method (or calling a public method which in turn calls the private method)?
Bill
@Konrad: As I detail in my own answer (http://stackoverflow.com/questions/2000137/overriding-private-methods-in-java/2002872#2002872), I created a scenario where I was calling an instance of a derived class which contained its own new private method (not overridden), but, which inherited a public method that called the private method. I called the public method on an instance of the derived class, but it executed the parent's private method. I was surprised by this result.
Bill
A: 

A class is defined by what methods it makes available and how they behave. Not how those are implemented internally (e.g. via calls to private methods).

Because encapsulation has to do with behavior and not implementation details, private methods have nothing to do with the idea encapsulation. In a sense, your question makes no sense. It's like asking "How is putting cream in coffee not a violation of encapsulation?"

Presumably the private method is used by something that is public. You can override that. In doing so, you've changed behavior.

z5h
+3  A: 

A parent's private method cannot be accessed or inherited by a child class, inline 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?

There is no such restriction. You can do that without any problems, it's just not called "overriding".

Overridden methods are subject to dynamic dispatch, i.e. the method that is actually called is selected at runtime depending on the actual type of the object it's called on. With private method, that does not happen (and should not, as per your first statement). And that's what is meant by the statement "private methods can't be overridden".

Michael Borgwardt
+1  A: 

I think you're misinterpreting what that post says. It's not saying that the child class is "restricted from implementing its own method with the same name/signature."

Here's the code, slightly edited:

public class PrivateOverride {
  private static Test monitor = new Test();

  private void f() {
    System.out.println("private f()");
  }

  public static void main(String[] args) {
    PrivateOverride po = new Derived();
    po.f();
    });
  }
}

class Derived extends PrivateOverride {
  public void f() {
    System.out.println("public f()");
  }
}

And the quote:

You might reasonably expect the output to be “public f( )”,

The reason for that quote is that the variable po actually holds an instance of Derived. However, since the method is defined as private, the compiler actually looks at the type of the variable, rather than the type of the object. And it translates the method call into invokespecial (I think that's the right opcode, haven't checked JVM spec) rather than invokeinstance.

kdgregory
@kdgregory: I think this gets close to what I experienced, but as I describe in my answer to my own post(http://stackoverflow.com/questions/2000137/overriding-private-methods-in-java/2002872#2002872), I instantiated an instance of the child class and accessed an inherited public method which called the private method in question, but the result given was the parent's private method result, not the child's. I think the way I setup the constructor in the child may have created the same scenario you describe here, even though my object creation code is different syntax than what yours shows.
Bill
A: 

When the method is private, it's not visible to its child. So there is no meaning of overriding it.

GK
+2  A: 

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

Gregory Pakosz
A: 

I apologize for using the term override incorrectly and inconsistent with my description. My description describes the scenario. The following code extends Jon Skeet's example to portray my scenario:

class Base {
   public void callFoo() {
     foo();
   }
   private void foo() {
   }
}

class Child extends Base {
    private void foo() {
    }
}

Usage is like the following:

Child c = new Child();
c.callFoo();

The issue I experienced is that the parent foo() method was being called even though, as the code shows, I was calling callFoo() on the child instance variable. I thought I was defining a new private method foo() in Child() which the inherited callFoo() method would call, but I think some of what kdgregory has said may apply to my scenario - possibly due to the way the derived class constructor is calling super(), or perhaps not.

There was no compiler warning in Eclipse and the code did compile. The result was unexpected.

Bill
as I said in my answer, in C++ `callFoo()` would call `Child::foo()`
Gregory Pakosz
Yeah, you have to use `protected` for that sort of thing in Java. And the compiler couldn't warn you because it has no way of knowing what you intended; your code is perfectly valid.
Michael Myers