Why inner class can override private final method?
JavaOverridingInner ClassesFinalJava Problem Overview
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?
Java Solutions
Solution 1 - Java
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 aBoom
object (((Boom) inner).touchMe()
) theBoom.touchMe
is called (if it indeed was overridden, the cast wouldn't matter).
Related question:
Solution 2 - Java
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.
Solution 3 - Java
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.
Solution 4 - Java
You can override the method because it is private
to each class.
Solution 5 - Java
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!