【问题标题】:Why can’t we override a base class method with private extended class method?为什么我们不能用私有扩展类方法覆盖基类方法?
【发布时间】:2011-07-09 08:39:13
【问题描述】:
class One {
    void foo() { }
}
class Two extends One {
    private void foo() { /* more code here */ }
}

为什么上面sn-p的代码错了?

【问题讨论】:

  • 你不能降低java中方法的可见性,你可以增加它,可见性顺序(最低->最高):私有,包私有(即无修饰符),受保护,公共。

标签: java methods overriding


【解决方案1】:

这段代码的问题是,如果它是合法的,如果你通过One 基类间接访问它,Java 将无法尊重fooprivate 修饰符。例如,如果我要写

One obj = new Two();
obj.foo();

那么我们就会遇到麻烦,因为我们会间接调用Twofoo 方法foo,因为当编译器检查obj.foo() 行时,它会查看One 以确定是否@ 987654330@ 可访问,而不是 Two。这样做的原因是编译器不能总是告诉 obj 可能指向什么 - 例如,如果我写了类似的东西

One obj = Math.random() < 0.5? new One() : new Two();
obj.foo();

那么编译器就无法知道obj 是指向One 还是Two。因此,它在检查访问说明符时遵循One。如果确实允许我们在Two 中将foo 标记为私有,那么编译器将错误地允许我们通过obj 调用它,它的类型为One,从而绕过只有对象本身可以调用@987654342 的保证@ 方法。

【讨论】:

  • 真正的问题是在 java 中不允许降低可见性。即使第一个方法受到保护而第二个包是私有的,编译器也可以编译,但不允许声明。
  • @bestsss- 是的,没错,但这个决定背后的原因是对上述逻辑的扩展。
【解决方案2】:

它会破坏多态性。

如果你有一个 Two 实例存储在一个 Two 变量中,那么 foo 不能被调用是有意义的。但是,如果您将 Two 实例存储在 One 变量中,则您只知道 One。但是一个人有一个公共的 foo,可以调用。这将是不一致的,而且会很奇怪。

【讨论】:

    【解决方案3】:

    因为继承是一个的关系。任何人都可以通过引用One 来引用Two 的实例:

    One v = new Two();
    

    如果您在 v 引用上调用 foo 方法,程序会做什么?你违反了 One 的公共合约,它保证 One 的每个实例都有一个(这里是包保护的)foo 方法。这就是编译器禁止它的原因。

    【讨论】:

      【解决方案4】:

      我将尝试结合其他答案的想法,得出一个答案。

      首先,让我们看看代码中发生了什么。

      看一下代码

      One 类有一个包私有的foo 方法:

      class One {
          // The lack of an access modifier means the method is package-private.
          void foo() { }
      }
      

      作为One 类的子类的Two 类和foo 方法被覆盖,但具有访问修饰符private

      class Two extends One {
          // The "private" modifier is added in this class.
          private void foo() { /* more code here */ }
      }
      

      问题

      Java 语言不允许子类降低子类中方法、字段或类的可见性,因此,Two 类降低foo 方法的可见性是不合法的。

      为什么降低可见性是个问题?

      考虑我们要使用One 类的情况:

      class AnotherClass {
        public void someMethod() {
           One obj = new One();
           obj.foo();  // This is perfectly valid.
        }
      }
      

      这里,在One 实例上调用foo 方法是有效的。 (假设AnotherClass 类与One 类在同一个包中。)

      现在,如果我们要实例化Two 对象并将其放入One 类型的obj 变量中呢?

      class AnotherClass {
        public void someMethod() {
           One obj = new Two();
           obj.foo();  // Wait a second, here...
        }
      }
      

      Two.foo 方法是私有的,但是,One.foo 方法将允许访问该方法。我们这里有问题。

      因此,在考虑继承时允许降低可见性并没有多大意义。

      链接

      【讨论】:

      • +1 作为写过其他答案之一的人,这是一个很好的总结,写得很好。感谢您将这些放在一起!
      【解决方案5】:

      给定的答案为您提供了为什么不能逐个扩展的技术解释。我想让你理解为什么这是不可能的,因为面向对象的模式而不是因为语言本身。

      通常,One 类是一个类的一般定义,它带有外部世界的访问器、方法。扩展此类的子类必须为外部世界提供相同的访问器。 Two 在您的示例中扩展了 One,这意味着 Two 提供了与 One 一样的外部世界访问器。如果您要更改 One 的访问器的可见性,外部世界将无法再访问您的类,因为它们习惯于使用 One 类型的对象进行访问。

      【讨论】:

        猜你喜欢
        • 2018-07-08
        • 2015-03-09
        • 2010-10-28
        • 1970-01-01
        • 2011-12-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多