abstract class Base{
protected abstract void a();
}
class Child extends Base{
@Override
public void a(){
//why is this valid
}
}
为什么我们不能降低可见度但可以增加它?
此外,我需要实现模板模式,其中可见的公共方法只能是基类。
示例:
abstract class Base{
public void callA(){
//do some important stuff
a();
}
protected abstract void a();
}
class Child extends Base{
@Override
public void a(){
//why is this valid
}
}
现在,如果java允许增加可见性,那么有两种方法可以公开显示吗?
我知道界面是一种解决方案,但还有其他方法吗?
答案 0 :(得分:22)
为什么不允许降低可见性已在其他响应中解释(它会破坏父类的合同)。
但为什么允许增加方法的可见性?首先,它不会破坏任何合同,因此没有理由不允许它。有时,它可以很方便,当在子类中有意义的方法不受保护时。
其次,不允许它可能会产生副作用,有时无法扩展类并同时实现接口:
interface Interface1 {
public void method();
}
public class Parent {
protected abstract void method();
}
public class Child extends Parent implements Interface1 {
@Override
public void method() {
}
//This would be impossible if the visibility of method() in class Parent could not be increased.
}
关于你的第二个问题,你无能为力。您必须相信实现子类的人不会做任何破坏您的实现的事情。即使java不允许提高可见性,这仍然无法解决您的问题,因为可以创建一个具有不同名称的公共方法来调用抽象方法:
class Child extends Base{
@Override
protected void a(){
}
public void a2() {
a(); //This would have the same problems that allowing to increase the visibility.
}
}
答案 1 :(得分:12)
如果基类对可见性做出承诺,那么子类不能破坏该承诺并仍然满足Liskov替换原则。如果承诺被破坏,则不能在承诺方法暴露的任何情况下使用子类。
子类IS-A基类。如果基类公开了一个方法,那么子类也必须公开。
Java或C ++没有出路。我猜在C#中也是如此。
答案 2 :(得分:3)
为什么我们不能降低可见度但可以增加它?
假设可以降低可见性。然后查看以下代码:
class Super {
public void method() {
// ...
}
}
class Sub extends Super {
@Override
protected void method() {
// ...
}
}
假设您将在另一个包中使用另一个类来使用这些类:
Super a = new Sub();
// Should this be allowed or not?
a.method();
要检查是否允许方法调用,编译器会查看您调用它的变量的类型。变量a
的类型为Super
。但是a
引用的实际对象是Sub
,并且方法是protected
,所以你可以说它不应该被允许从一个不相关的类调用该方法。包。为了解决这种奇怪的情况,禁止使被覆盖的方法不那么明显。
请注意,反过来(使方法更加明显)不会导致同样的问题。
答案 3 :(得分:1)
由于Java允许超类引用指向子类对象。因此,限制不应该从compile-time
增加到runtime
..
让我们看一下这个例子: -
public class B {
public void meth() {
}
}
class A extends B {
private void meth() { // Decrease visibility.
}
}
现在,您创建了一个类A
的对象,并为其指定了类B
的引用。
让我们看看如何: -
B obj = new A(); // Perfectly valid.
obj.meth(); // Compiler only checks the reference class..
// Since meth() method is public in class B, Compiler allows this..
// But at runtime JVM - Crashes..
现在,由于compiler
仅检查参考变量的类型,并检查该类(B类)中方法的可见性,然后不检查reference
obj所引用的对象。所以,它并不担心这一点。它在运行时留给JVM来解析适当的方法。 。
但在运行时,JVM实际上会尝试调用类meth
的{{1}} 方法,因为对象属于A类。但是,现在发生了什么... BooooOOMM ---> JVM崩溃 ..因为A
方法在meth
中是私有的...
这就是为什么不允许降低能见度..