[英]Why can’t we override a base class method with private extended class method?
class One {
void foo() { }
}
class Two extends One {
private void foo() { /* more code here */ }
}
为什么上面的代码片段是错误的?
我将尝试结合其他答案中的想法来得出一个答案。
首先,让我们看看代码中发生了什么。
看一下代码
One
类有一个包私有的foo
方法:
class One {
// The lack of an access modifier means the method is package-private.
void foo() { }
}
Two
类是One
类的子类, foo
方法被覆盖,但具有访问修饰符private
。
class Two extends One {
// The "private" modifier is added in this class.
private void foo() { /* more code here */ }
}
问题
Java 语言不允许子类降低子类中方法、字段或类的可见性,因此,降低foo
方法可见性的Two
类是不合法的。
为什么降低能见度是一个问题?
考虑我们要使用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
方法允许访问该方法。 我们这里有问题。
因此,在考虑继承时允许降低可见性没有多大意义。
链接
这段代码的问题在于,如果它是合法的,那么如果您通过One
基类间接访问它,Java 将无法尊重foo
的private
修饰符。 例如,如果我要写
One obj = new Two();
obj.foo();
然后我们会遇到麻烦,因为我们将间接调用Two
的private
方法foo
,因为当编译器检查obj.foo()
它会查看One
以确定foo
是否可访问,而不是在Two
。 这样做的原因是编译器不能总是告诉obj
可能指向什么 - 例如,如果我写了类似的东西
One obj = Math.random() < 0.5? new One() : new Two();
obj.foo();
那么编译器就无法知道obj
指向One
还是指向Two
。 因此,它在检查访问说明符时遵循One
。 如果我们确实被允许在Two
标记foo
private ,那么编译器会错误地允许我们通过obj
调用它,它的类型为One
,绕过只有对象本身可以调用private
方法的保证。
给出的答案为您提供了为什么不能一一扩展的技术解释。 我想让你理解为什么这是不可能的,因为面向对象模式而不是因为语言本身。
通常,类 One 是一个类的一般定义,它带有外部世界的访问器、方法。 扩展此类的子类必须为外部世界提供相同的访问器。 在您的示例中,两个扩展了一个,这意味着两个为外部世界提供了与 One 相同的访问器。 如果您要更改 One 访问器的可见性,外部世界将无法再访问您的类,因为它们习惯于对类型为 One 的对象进行访问。
它会破坏多态性。
如果你有一个 Two 实例存储在 Two 变量中,那么不能调用 foo 是有道理的。 但是,如果将 Two 实例存储在 One 变量中,则您只知道 One。 但是 One 有一个公共 foo,可以调用它。 这将是不一致的,并且真的很奇怪。
因为继承是一种关系。 任何人都可以通过引用One
来引用Two
的实例:
One v = new Two();
如果你在 v 引用上调用 foo 方法,程序会做什么? 你破坏了 One 的公共契约,它保证 One 的每个实例都有一个(这里是包保护的)foo 方法。 这就是编译器禁止它的原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.