为什么Java允许增加子类中受保护方法的可见性?

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允许增加可见性,那么有两种方法可以公开显示?

我知道界面是一个解决方案,但还有其他方法吗?

为什么不允许降低可见性已在其他响应中解释(它将破坏父类的合同)。

但为什么允许它增加方法的可见性? 首先,它不会破坏任何合同,因此没有理由不允许它。 有时,它可以很方便,当在子类中有意义的方法不受保护时。

其次,不允许它可能产生副作用,有时无法扩展类并同时实现接口:

 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. } } 

如果基类做出关于可见性的承诺,那么子类不能破坏该承诺并仍然满足Liskov替换原则。 如果承诺被破坏,则不能在承诺方法公开的任何情况下使用子类。

子类IS-A基类。 如果基类公开了一个方法,那么子类也必须公开。

在Java或C ++中没有出路。 我猜在C#中也是如此。

为什么我们不能降低能见度但可以增加它?

假设可以降低可见性。 然后看下面的代码:

 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 ,因此您可以说不应该允许它从包外的不相关类调用该方法。 为了解决这种奇怪的情况,禁止使被覆盖的方法不那么明显。

请注意,反过来(使方法更加可见)不会导致相同的问题。

由于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所reference 的对象类型 。所以,它不是担心这个问题。它在运行时留给JVM来解决相应的方法。

但是在运行时 ,JVM实际上会尝试调用A meth方法,因为对象是A类。但是,现在发生了什么…… BooooOOMM —> JVM崩溃 ..因为在方法class A meth方法是私有class A 。 ..

这就是为什么不允许降低能见度的原因。