override this!
May 19, 2006 11:57 PM   Subscribe

java: If a private method can't be overriden, but it's possible to create a method in a subclass with the same signature, what's the difference?

I mean, isn't that the same thing as overriding the method, for all practical purposes?

Here's an example from the Whizlabs exam engine:

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

public class Test extends SuperTest{
protected void f(){
System.out.println("Test");
}
public static void main(String args[]{
Test s=new Test();
s.f();
}
}

The answer justifies this by saying "A subclass does not inherit private methods of its superclass. However, it can define a matching method, though it would not be actual overriding."

Okay, then, call it what you want, but I'm confused an authority that says I can't do something, except when I point to it and call it something else.

Obviously I'm missing something here, but I don't know what it is. The book I'm reading also seems to dance around this issue.
posted by bingo to Computers & Internet (20 answers total)
 
One of the big differences is if you only know of the class as an instance of the superclass, then you can't access the method that is implemented in both of them (and possibly has greater visibility in the subclass).
posted by freshgroundpepper at 12:07 AM on May 20, 2006


You're missing something. If you'd overridden the method, you could call parent.f(). In your example, you can't, since the parent is private.
posted by majick at 12:10 AM on May 20, 2006


super.f() rather. Sorry, I'm a bit bleary-eyed.
posted by majick at 12:11 AM on May 20, 2006


Ex: Say you have an Apple which is a subclass of Fruit. If Fruit has a private method of "eat()", you can also write an "eat()" method on the Apple class. If you've got an instance of a Fruit (which happens to be an Apple), you can't call "eat()" on it unless you check the type and subclass it to an Apple.


Also, the subclass can't call this.super() to leverage the logic in the superclass.
posted by freshgroundpepper at 12:12 AM on May 20, 2006


I also wonder which method will be called if a method in the parent class invokes f(). (I have no idea; it's been ages since I did Java stuff.) If the parent gets its own f(), then it's not overriding, it's just scoping. If the parent's methods end up invoking the subclass's f(), then it smells like overriding to me.
posted by hattifattener at 12:14 AM on May 20, 2006


heh, whoops, I screwed up the super call as well (I was thinking of calling the constructor of the superclass), but you get the idea.
posted by freshgroundpepper at 12:15 AM on May 20, 2006


Response by poster: freshgroundpepper: Ex: Say you have an Apple which is a subclass of Fruit. If Fruit has a private method of "eat()", you can also write an "eat()" method on the Apple class. If you've got an instance of a Fruit (which happens to be an Apple), you can't call "eat()" on it unless you check the type and subclass it to an Apple.

I don't get it...

Fruit fruit = new Fruit();
Apple apple = new Apple();
fruit.eat();
apple.eat();

Won't that code work fine whether Apple got its eat method from Fruit, or whether it came with its own?

majick: If you'd overridden the method, you could call super.f(). In your example, you can't, since the parent is private

Fair enough...is that the whole story?
posted by bingo at 12:20 AM on May 20, 2006


You can see that it's not the same as overriding if you try the following code. For almost all purposes, a private method isn't connected to identically-named methods in its subclasses -- the private flag tells the compiler "hey, only this class knows about this method, so if this class has any references to f(), you know exactly which f() I mean and don't need to check at runtime like you do for protected or public methods".

public class Test extends SuperTest {
protected void f() {
System.out.println("f Test");
}

protected void g() {
System.out.println("g Test");
}

public static void main(String args[]){
Test s=new Test();
s.h();
}
}
class SuperTest {
private void f() {
System.out.println("f SuperTest");
}

protected void g() {
System.out.println("g SuperTest");
}

public void h() {
this.f();
this.g();
}
}

In h()'s calls, f() is private and hence the child class can't override it; g() is protected and can be overridden.
posted by inkyz at 12:20 AM on May 20, 2006


The power of overriding (and subclassing) comes because you are adhering to a contract (defined by the superclass) that says that it, and all subclasses will adhere to that particular contract (whether or not they provide their own implementation).

As long as you know it's a Fruit, you know you can eat() it, whether or not the actual details of the eating are defined in the Fruit or the Apple. If the Fruit's eat method is private, and even if you (the programmer) knows that you can eat() all concrete subclasses of Fruit, you still can't eat() the Fruit without casting it to a particular subclass (and probably using some sort of reflection to figure out what kind of subclass it actually is).

Having a private method isn't preventing any subclass from implementing a method with the same name, the subclasses don't even know what private methods it's superclasses have. The power of overridding is allowing a default implementation to be put in place by a superclass, and then allowing subclasses to optionally define their own way of doing things.

What you're talking about isn't overriding, because the private method wasn't a valid target to be called from anything outside of private scope in the first place.
posted by freshgroundpepper at 12:57 AM on May 20, 2006


fruit.eat(); will fail. (private; only the fruit class can call it)
apple.eat(); will succeed (if public)
posted by beerbajay at 1:40 AM on May 20, 2006


Inkyz's answer gets to the most important issue, I believe. This is one of those things where more details makes things clearer, I can't recommend "Inside The C++ Object Model" by Lippman highly enough.

Overriding is a dynamic phenonmenon: a particular line of code, say
  obj.eat()
might call different overrides each time it's executed depending on the value of obj. In the "same signature" case you are adding a function eat to a new scope. Scoping is static in java. The scope of eat in that same line of code is known at compile time.

In other words I could go through your program and replace each instance of the eat identifier, depending on context with either eat_the_first_private_one or eat_my_second_one and the program would have identical behavior.
posted by Wood at 3:38 AM on May 20, 2006



Fruit fruit = new Fruit();
Apple apple = new Apple();
fruit.eat();
apple.eat();

Won't that code work fine whether Apple got its eat method from Fruit, or whether it came with its own?


No, "fruit.eat()" will fail. In addition:

Fruit A = new Apple();
A.eat();

Will also fail (not compile)
posted by delmoi at 10:16 AM on May 20, 2006


Response by poster: delmoi: even if the Fruit class is concrete, and has its own version of eat() ?
posted by bingo at 10:25 AM on May 20, 2006


bingo: Yes, if Fruit.eat() is private then you can't call it, and a non-private method eat() in Apple doesn't change that.
posted by Khalad at 10:52 AM on May 20, 2006


Response by poster: Khalad: Uh...no, the fact that a method is private doesn't mean it can't be called, it just means that it can't be called from outside the class.

This compiles fine:

class Fruit {
private void eat() {System.out.println("eat fruit");}
public static void main( String [] args ) {
Fruit myfruit = new Fruit();
myfruit.eat();
}
}
posted by bingo at 11:08 AM on May 20, 2006


Response by poster: More to the point:


class Fruit {

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

public static void main( String [] args ) {
Fruit myfruit = new Fruit();
Apple myapple = new Apple();
myfruit.eat();
myapple.eat();
}
}

class Apple {

public void eat() {System.out.println("eat apple");}
}


when Fruit is run, the output is:

eat fruit
eat apple
posted by bingo at 11:14 AM on May 20, 2006


Overriding means covering a visible method of your superclass with your own method. A private function cannot be overridden by definition, because it is never 'visible'. There are no external calls to override. The keyword that prevents non-private methods from being overridden is final.
posted by fleacircus at 11:19 AM on May 20, 2006


Best answer: Private methods (and static methods) are statically ("early", "compile-time") bound in Java; public or protected non-final non-static methods are dynamically ("late", "run-time") bound.

(Note that this differs from C++, in which private methods, like public and protected methods, are dynamically bound so long as they are virtual.)

With static binding, the method called is determined by the static type of the variable (static type: in java, the "reference type"; in C++, the type of the pointer).

Given a class B and a a class D that inherits from B, in the the following code, the static type is B and the dynamic or object type is D; "b" is the reference the a "D" object created on the heap by the new operator:
B b = new D() ;
Statically binding private methods is apparently a conscious design choice, although coming from a C++ background, it seems to me like a mis-feature. In particular, it makes the implementation of the Template Method Pattern and similar patterns less straightforward. I'd be very interested in hearing an explanation for why this choice was made.


The test's answer, that private methods are not inherited, is misleading. The method is inherited, but it (correctly, because it's private) can't be called from outside the base class and (strange Java mis-feature) is statically bound at call-sites within the base class.

This page explains how the Java Virtual Machine implements method calls; private methods essentially are invoked like static methods but with the implicit "this" parameter passed as an argument. Scroll down to "Other forms of method invocation", and see the following page for a fuller discussion and example:
Invokespecial is used in three situations in which an instance method must be invoked based on the type of the reference, not on the class of the object. The three situations are:

1. invocation of instance initialization () methods
2. invocation of private methods
3. invocation of methods using the super keyword </blockquote

posted by orthogonality at 11:43 AM on May 20, 2006


Bingo, I think the reason that your last example works is because it is Fruit's main method that is called it's private eat()

Try creating the Fruit and Apple objects from a third class, or even from a main method in Apple. I think your results will be different.
posted by utsutsu at 1:25 PM on May 20, 2006


Response by poster: Okay...I don't completely understand orthogonality's answer, but I'm marking it best because I think it most closely addresses what I was really asking. Thanks everyone.
posted by bingo at 10:42 AM on May 21, 2006


« Older downloads sans spyware?   |   How do I stop Outlook from continuing to try to... Newer »
This thread is closed to new comments.