class One {
void foo() { }
}
class Two extends One {
private void foo() { /* more code here */ }
}
为什么上面的代码片段错了?为什么不能用私有扩展类方法重写基类方法?
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语言不允许子类,以减少在子类中的方法,字段或类的可见性,因此,Two
类减少foo
方法的能见度不合法。
为什么要降低可见性是一个问题?
考虑我们要使用的One
类情况:
class AnotherClass {
public void someMethod() {
One obj = new One();
obj.foo(); // This is perfectly valid.
}
}
这里,调用foo
方法上One
实例有效。 (假设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作为写过其他答案之一的人,这是一篇很好的总结,写得很好。感谢您将它们放在一起! – templatetypedef
非常精确,重点突出。 –
此代码的问题在于,如果它是合法的,那么如果您通过One
基类间接访问它,Java将无法尊重private
修饰符foo
。例如,如果我写
One obj = new Two();
obj.foo();
那么我们就会有麻烦,因为我们会被调用private
方法Two
foo
间接,当编译器检查它着眼于One
以确定线路obj.foo()
自如果foo
可访问,则不在Two
。这样做的原因是,编译器不能总是分不清什么obj
可以在被人指指点点 - 如果,例如,我喜欢写东西
One obj = Math.random() < 0.5? new One() : new Two();
obj.foo();
那么编译器无法知道是否在One
obj
点或一个Two
。因此,在检查访问说明符时,它会遵循One
。如果我们确实允许在Two
中标记foo
private,那么编译器会错误地允许我们通过obj
(它的类型为One
)调用它,绕过保证只有对象本身可以调用private
方法。
真正的问题是在Java中不允许降低可见性。即使第一个方法被保护,第二个包为私有,编译器也可以编译,但是不允许声明。 – bestsss
@ bestsss-是的,这是真的,但这个决定背后的推理是对上述逻辑的扩展。 – templatetypedef
它会破坏多态性。
如果你有一个Two实例存储在一个Two变量中,那么foo不能被调用是有意义的。但是,如果您将One实例存储在One变量中,那么您只知道One。但是,一个人拥有公共福利,这可以被称为。这将是一个不一致,而且会很奇怪。
因为继承是是的关系。任何人都可以通过参考指的Two
一个实例One
:
One v = new Two();
什么会的程序做,如果你呼吁V基准foo的方法是什么?你打破了One的公共契约,保证One的每个实例都有一个(这里是封装保护的)foo方法。这就是编译器禁止它的原因。
给出的答案给你技术上的解释,为什么你不能一个接一个的扩展。我想给你一个理解,为什么这是不可能的,因为面向对象的模式,而不是由于语言本身。
通常,第一类是带有其访问器的类的一般定义,即方法到外部世界。扩展这个类的子类必须为外部世界提供相同的访问者。两个在你的例子中扩展一个,这意味着,Two提供了和One一样的外部世界的访问器。如果您要更改One的访问器的可见性,则外部世界将无法再访问您的类,因为它们习惯使用类型为One的对象进行访问。
您无法降低Java中某个方法的可见性,您可以增加它,可见性顺序(最低 - >最高):私有,私有包(即无修饰符),受保护,公共。 – bestsss