66

I wondered if it makes sense to declare a private method as final as well, and I thought it doesn't make sense. But I imagined there's an exclusive situation and wrote the code to figure it out:

public class Boom {

    private void touchMe() {
        System.out.println("super::I am not overridable!");
    }

    private class Inner extends Boom {

        private void touchMe() {
            super.touchMe();
            System.out.println("sub::You suck! I overrided you!");
        }
    }

    public static void main(String... args) {
        Boom boom = new Boom();
        Boom.Inner inner = boom.new Inner();
        inner.touchMe();
    }
}

It compiled and worked. "I should make touchMe() final" I thought and did it:

public class Boom {

    private final void touchMe() {
        System.out.println("super::I am not overridable!");
    }

    private class Inner extends Boom {

        private void touchMe() {
            super.touchMe();
            System.out.println("sub::You suck! I overrided you!");
        }
    }

    public static void main(String... args) {
        Boom boom = new Boom();
        Boom.Inner inner = boom.new Inner();
        inner.touchMe();
    }
}

and it also works and tells me

chicout@chicout-linlap:~$ java Boom
super::I am not overridable!
sub::You suck! I overrided you!

why?

Vipin
  • 4,851
  • 3
  • 35
  • 65
chicout
  • 937
  • 7
  • 16
  • It's "hiding" or "shadowin" or something. Does kind of show why extending the outer class is a bit evil (even in enums, really). / Try `Boom inner = boom.new Inner();` – Tom Hawtin - tackline Mar 01 '12 at 21:05
  • 23
    Good example of why you should use the @Override annotation. Ensure you're actually overriding the method – Shawn Mar 01 '12 at 21:06
  • Should it not write `super...` two times? *Update* No. Mea culpa. I see. – DerMike Mar 01 '12 at 21:08
  • The explanations given here leave something to be desired. Most of them state that the inner class's method is a "separate method" from the one in the containing class, one that just happens to share the same name. (Same *signature*, I might add.) However, an overriding method is also a separate method that just happens to have the same name. The magic of overriding is not some underlying "sameness," it is in the behavior of the dispatch mechanism. – Nate C-K Mar 07 '12 at 13:57
  • this `super.touchMe();`... – Yousha Aleayoub Oct 31 '18 at 13:08

5 Answers5

87

Private methods can not be overridden (private methods are not inherited!) In fact, it makes no difference if you declare a private method final or not.

The two methods you have declared, Boom.touchMe and Boom.Inner.touchMe are two completely separate methods which just happen to share the same identifier. The fact that super.touchMe refers to a different method than touchMe, is just because Boom.Inner.touchMe shadows Boom.touchMe (and not because it overrides it).

This can be demonstrated in a number of ways:

  • As you discovered yourself, if you change the methods to be public, the compiler will complain because you are suddenly trying to override a final method.

  • If you keep the methods private and add the @Override annotation, the compiler will complain.

  • As alpian points out, if you cast the Boom.Inner object to a Boom object (((Boom) inner).touchMe()) the Boom.touchMe is called (if it indeed was overridden, the cast wouldn't matter).

Related question:

Community
  • 1
  • 1
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • 13
    I may be wrong on this, but I believe a key misconception is that `super.touchMe()` means "Call the method this method overrides." While it often works out that way, it really means "Call the `touchMe()` method in the class this class extends." That's why you can call `super.touchMe()` - it just happens to also have a method (with the same signature). – corsiKa Mar 01 '12 at 21:06
  • 1
    Yes, thanks! I got it now. When I made it public I got the compile-time error. – chicout Mar 01 '12 at 21:11
  • 4
    It's also easy to see that Inner is not overriding Boom, adding @Override to the method generates a compiler error. – TDJoe Mar 01 '12 at 21:13
  • 4
    From the [Java Language Specification](http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.2): _"Members of a class that are declared private are not inherited by subclasses of that class."_ Behind the scenes, when `Inner.touchMe()` calls `super.touchMe()`, the compiler will generate an _accessor method_ with a unique name with default (package) access in the outer class that relays the call to the private method. It then changes `super.touchMe()` to call the accessor method. – Ted Hopp Mar 01 '12 at 23:10
8

I think the fact that there really are two separate methods here is nicely demonstrated by changing your main as follows:

public static void main(String... args) {
    Boom boom = new Boom();
    Boom.Inner inner = boom.new Inner();
    inner.touchMe();
    System.out.println("And now cast it...");
    ((Boom)(inner)).touchMe();
}

This now prints:

super::I am not overridable!
sub::You suck! I overrided you!
And now cast it...
super::I am not overridable!

And the reason that the call to super works in Inner is because you're looking up a method called touchMe in your super-class (Boom) which indeed exists and is visible to Inner as it is in the same class.

alpian
  • 4,668
  • 1
  • 18
  • 19
6

Private methods are invisible to subclasses, or indeed any other class, so they can have the same name, but are not over-riding one another.

Try adding the @Override annotation - you will get a compiler error.

DNA
  • 42,007
  • 12
  • 107
  • 146
  • 1
    "Private methods are invisible to ... any other class" - except and until you consider reflection. – user Mar 02 '12 at 08:55
  • True - but I think that's outside the scope of the original question, and wouldn't affect the over-riding issue. – DNA Mar 02 '12 at 09:06
2

You can override the method because it is private to each class.

Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
1

You have just declared another method with same name. You are able to call private member of the class because inner class is itself member of class. Hope this modification will explain it in details.

public class Boom {

    private final void touchMe() {
        System.out.println("super [touchMe] ::I am not overridable!");
    }

    public void overrideMe(){
        System.out.println("super [overrideMe]::I am overridable!");
    }

    private class Inner extends Boom {

        private void touchMe() {
            super.touchMe();
            System.out.println("sub [touchMe]::You suck! I overrided you!");
        }

        public void overrideMe(){
            System.out.println("sub [overrideMe] ::I overrided you!");
        }
    }

    public static void main(String... args) {
        Boom boom = new Boom();
        Boom.Inner inner = boom.new Inner();

        inner.touchMe();

        Boom newBoom = inner;
        newBoom.touchMe();
        newBoom.overrideMe();
    }
}



super [touchMe] ::I am not overridable!
sub [touchMe]::You suck! I overrided you!
super [touchMe] ::I am not overridable!
sub [overrideMe] ::I overrided you!
JProgrammer
  • 1,135
  • 1
  • 10
  • 27