有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

设计模式为什么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允许增加可见性,那么有两种方法是公开可见的

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


共 (4) 个答案

  1. # 1 楼答案

    其他响应中已经解释了为什么不允许降低可见性(这将破坏父类的契约)

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

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

    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.
          }
    }
    
  2. # 2 楼答案

    Why is that we can't reduce the visibility but can increase it?

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

    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. # 3 楼答案

    因为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)中方法的可见性,而它不检查referenceobj引用的对象是什么类型的。。所以,它并不担心。。由JVM在运行时解析适当的方法

    但是在运行时,JVM实际上会尝试调用类methA方法,因为对象是类A的。。但是,现在发生了什么BOOOOOMM--->;JVM崩溃。。因为meth方法在class A中是私有的

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

  4. # 4 楼答案

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

    子类是一个基类。如果基类公开方法,那么子类也必须公开方法