为什么我们不能用私有扩展类方法覆盖基类方法?

时间:2011-03-05 10:26:44

标签: java methods override

class One {
    void foo() { }
}
class Two extends One {
    private void foo() { /* more code here */ }
}

为什么上面的代码片段错了?

5 个答案:

答案 0 :(得分:11)

我将尝试将其他答案中的想法合并为一个答案。

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

查看代码

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

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

Two类的子类Onefoo方法被覆盖,但具有访问修饰符private

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

问题

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

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

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

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

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

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

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

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

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

<强>链接

答案 1 :(得分:1)

此代码的问题在于,如果它是合法的,如果您通过private基类间接访问它,Java将无法尊重foo的{​​{1}}修饰符。例如,如果我要写

One

然后我们遇到麻烦,因为我们会间接调用One obj = new Two(); obj.foo(); private foo方法,因为当编译器检查行Two时它看起来像在obj.foo()确定One是否可访问,而不是foo。原因是编译器不能总是告诉Two可能指向的是什么 - 例如,如果我写了类似

的内容
obj

然后编译器无法知道One obj = Math.random() < 0.5? new One() : new Two(); obj.foo(); 是指向obj还是One。因此,在检查访问说明符时,它会推迟到Two。如果确实允许我们在One中标记foo私有,则编译器会错误地允许我们通过类型为Two的{​​{1}}来调用它,绕过保证只有对象本身可以调用obj方法。

答案 2 :(得分:1)

给出的答案为您提供技术解释,说明为什么不能逐一扩展。我想让你理解为什么由于面向对象的模式而不是因为语言本身而无法实现这一点。

通常,类One是类的一般定义,具有访问器,方法和外部世界。扩展此类的子阶段必须为外部世界提供相同的访问者。两个扩展在你的例子中,一个意思是,两个提供与外部世界相同的访问者,就像One一样。如果您要更改One的访问者的可见性,则外部世界将无法再访问您的类,因为他们习惯使用类型为One的对象。

答案 3 :(得分:0)

它会破坏多态性。

如果你有两个实例存储在一个Two变量中,那么foo就不能被调用了。但是如果你在One变量中存储一个Two实例,你只能知道一个。但是,One有一个公共foo,可以称之为。这将是一个不一致的,并且会非常奇怪。

答案 4 :(得分:0)

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

One v = new Two();

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