为什么内部类可以覆盖私有final方法?

chi*_*out 66 java overriding final inner-classes

我想知道将私有方法声明为最终是否有意义,我认为这没有意义.但我想象有一个独特的情况,并编写代码来弄清楚:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

它编译和工作."我应该让touchMe()最终成功"我想到并做到了:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

它也有效并告诉我

chicout@chicout-linlap:~$ java Boom
super::I am not overridable!
sub::You suck! I overrided you!
Run Code Online (Sandbox Code Playgroud)

为什么?

aio*_*obe 87

私有方法不能被重写(私有方法不会被继承!)事实上,如果你声明一个私有方法final,它没有任何区别.

这两种方法你声明,Boom.touchMe以及Boom.Inner.touchMe两种完全不同的方法,这只是碰巧共享相同的标识.super.touchMe引用不同方法的事实touchMe只是因为Boom.Inner.touchMe 阴影 Boom.touchMe(而不是因为它覆盖它).

这可以通过多种方式证明:

  • 当你发现你自己,如果你改变了方法进行公开,编译器会抱怨,因为你突然试图重写final方法.

  • 如果将方法保密并添加@Override注释,编译器将会抱怨.

  • 正如alpian指出的那样,如果你将Boom.Inner对象强制转换为一个Boom对象(((Boom) inner).touchMe()),Boom.touchMe那么就会被调用(如果确实被覆盖了,那么强制转换就无所谓了).

相关问题:

  • 我可能错了,但我认为一个关键的误解是`super.touchMe()`意味着"调用此方法覆盖的方法".虽然它通常以这种方式运行,但它实际上意味着"在这个类扩展的类中调用`touchMe()`方法." 这就是为什么你可以调用`super.touchMe()` - 它恰好也有一个方法(具有相同的签名). (13认同)
  • 也很容易看出Inner没有覆盖Boom,将@Override添加到该方法会产生编译器错误. (4认同)
  • 从[Java语言规范](http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.2):_​​"子类的成员不会被子类继承"_在幕后,当`Inner.touchMe()`调用`super.touchMe()`时,编译器将生成一个_accessor方法_,该方法具有唯一的名称,并且在外部类中具有默认(包)访问权限对私有方法的调用.然后它改变`super.touchMe()`来调用accessor方法. (4认同)

alp*_*ian 8

我认为通过更改主要内容可以很好地证明这里有两种不同的方法,如下所示:

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();
}
Run Code Online (Sandbox Code Playgroud)

现在打印:

super::I am not overridable!
sub::You suck! I overrided you!
And now cast it...
super::I am not overridable!
Run Code Online (Sandbox Code Playgroud)

而且该呼叫的原因super的作品Inner是因为你正在寻找一个调用的方法touchMe在你的超一流(Boom),这的确存在,并且是可见的Inner,因为它是在同一类.


DNA*_*DNA 6

私有方法对于子类或实际上任何其他类是不可见的,因此它们可以具有相同的名称,但不会相互重叠.

尝试添加@Override注释 - 您将收到编译器错误.