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

时间:2012-10-08 11:25:47

标签: java design-patterns

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

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

4 个答案:

答案 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中是私有的...

这就是为什么不允许降低能见度..