【问题标题】:Why inner class can override private final method?为什么内部类可以覆盖私有最终方法?
【发布时间】:2012-03-20 09:48:55
【问题描述】:

我想知道将私有方法也声明为 final 是否有意义,我认为这没有意义。但我想象有一个排他的情况,并写了代码来解决它:

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();
    }
}

它编译并工作。 “我应该让 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();
    }
}

它也有效并告诉我

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

为什么?

【问题讨论】:

  • 这是“隐藏”或“隐藏”之类的。有点说明为什么扩展外部类有点邪恶(即使在枚举中,真的)。 / 试试Boom inner = boom.new Inner();
  • 为什么应该使用@Override 注释的好例子。确保您实际上覆盖了该方法
  • 不应该写super...两次吗? 更新不,过失。我明白了。
  • 这里给出的解释有待改进。他们中的大多数声明内部类的方法是与包含类中的方法“分离的方法”,只是碰巧共享相同的名称。 (相同的 signature,我可能会添加。)但是,覆盖方法也是一个单独的方法,只是碰巧具有相同的名称。覆盖的魔力不是某种潜在的“相同性”,而是调度机制的行为。
  • 这个super.touchMe();...

标签: java overriding inner-classes final


【解决方案1】:

私有方法不能被覆盖(私有方法不能被继承!)其实,私有方法声明不final没有区别。

您声明的两个方法Boom.touchMeBoom.Inner.touchMe 是两个完全独立的方法,它们恰好共享相同的标识符。 super.touchMe 指的是与 touchMe 不同的方法这一事实只是因为 Boom.Inner.touchMe shadows Boom.touchMe(而不是因为它覆盖了它)。

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

  • 正如您自己发现的那样,如果您将方法更改为公开的,编译器会抱怨,因为您突然尝试覆盖 final 方法。

  • 如果您保持方法私有并添加@Override 注解,编译器会报错。

  • 1234563 .

相关问题:

【讨论】:

  • 我可能错了,但我认为一个关键的误解是super.touchMe() 的意思是“调用此方法覆盖的方法”。虽然它通常以这种方式运行,但它实际上意味着“在此类扩展的类中调用 touchMe() 方法”。这就是为什么您可以调用super.touchMe() - 它恰好也有一个方法(具有相同的签名)。
  • 好的,谢谢!我现在明白了。当我公开它时,我得到了编译时错误。
  • 也很容易看出Inner没有覆盖Boom,在方法中添加@Override会产生编译错误。
  • 来自Java Language Specification“声明为私有的类的成员不会被该类的子类继承。” 在幕后,当Inner.touchMe() 调用@ 987654338@,编译器将生成一个具有唯一名称的访问器方法,在将调用中继到私有方法的外部类中具有默认(包)访问权限。然后它更改super.touchMe() 以调用访问器方法。
【解决方案2】:

你刚刚声明了另一个同名的方法。您可以调用类的私有成员,因为内部类本身就是类的成员。希望这次修改能详细解释一下。

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!

【讨论】:

    【解决方案3】:

    我认为通过如下更改 main 可以很好地证明这里确实有两种不同的方法:

    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();
    }
    

    现在打印:

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

    super 的调用在Inner 中起作用的原因是因为您正在超类(Boom)中查找一个名为touchMe 的方法,该方法确实存在并且对@987654327 可见@ 因为它在同一个类中。

    【讨论】:

      【解决方案4】:

      私有方法对子类或任何其他类都是不可见的,因此它们可以具有相同的名称,但不能相互覆盖。

      尝试添加 @Override 注释 - 你会得到一个编译器错误。

      【讨论】:

      • “私有方法对...任何其他类都是不可见的”——除非你考虑反射。
      • 是的 - 但我认为这超出了原始问题的范围,不会影响最重要的问题。
      【解决方案5】:

      您可以覆盖该方法,因为它是每个类的private

      【讨论】:

        猜你喜欢
        • 2014-08-31
        • 2012-10-09
        • 2014-11-03
        • 2019-12-11
        • 1970-01-01
        • 2016-12-23
        • 2016-12-23
        • 2010-10-22
        • 2011-07-09
        相关资源
        最近更新 更多