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

Nar*_*hai 16 java design-patterns

abstract class Base{
      protected abstract void a();
}

class Child extends Base{
      @Override
      public void a(){
          //why is this valid
      }
}
Run Code Online (Sandbox Code Playgroud)

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

此外,我需要实现模板模式,其中公共方法可见只能是基类.

例:

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
      }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果java允许增加可见性,那么有两种方法可以公开显示?

我知道接口是一个解决方案但是还有其他方法吗?

Pab*_*blo 26

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

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

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

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.
}
Run Code Online (Sandbox Code Playgroud)

关于你的第二个问题,你无能为力.您必须相信实现子类的人不会做任何破坏您的实现的事情.即使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.
      }
}
Run Code Online (Sandbox Code Playgroud)


duf*_*ymo 13

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

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

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


Jes*_*per 5

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

假设有可能降低能见度。然后看下面的代码:

class Super {
    public void method() {
        // ...
    }
}

class Sub extends Super {
    @Override
    protected void method() {
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

假设您将在另一个包中拥有另一个类,您将在其中使用这些类:

Super a = new Sub();

// Should this be allowed or not?
a.method();
Run Code Online (Sandbox Code Playgroud)

要检查是否允许方法调用,编译器会查看调用它的变量的类型。变量的类型aSuper。但是a引用的实际对象是 a Sub,并且方法是protected,因此您会说不应该允许从包外的不相关类调用该方法。为了解决这种奇怪的情况,禁止使覆盖的方法不那么可见。

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