Why Java allows increasing the visibility of protected methods in child class?

风格不统一 提交于 2019-12-17 09:46:28

问题


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

class Child extends Base{
      @Override
      public void a(){
          //why is this valid
      }
}

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

Also I need to implement Template pattern in which the public methods visible can only be of base class.

Example:

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

Now if java allows to increase visibility then there are two methods visible publicly??

I know interface is one solution but is there some other way out???


回答1:


Why decreasing visibility is not allowed is already explained in other responses (it would break the contract of the parent class).

But why it is allowed to increase the visibility of a method? First, it would not break any contract, so there is no reason to not allow it. It can be handy sometimes, when it makes sense in the child class for a method to not be protected.

Second, not allowing it could have the side effect of making impossible sometimes to extend a class and implement an interface at the same time:

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

About your second question, you can do nothing about it. You have to trust that the person who implements the child class doesn't do anything that breaks your implementation. Even if java wouldn't allow to increase visibility, that would still not fix your problem, because a public method with a different name could be created that calls the abstract method:

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:


If the base class makes a promise regarding visibility, then the subclass cannot break that promise and still satisfy the Liskov substitution principle. You can't use a subclass in any situation where the promised method is exposed if that promise is broken.

The subclass IS-A base class. If the base class exposes a method, so must the subclass.

There's no way out in Java or C++. I'd guess the same is true in C#.




回答3:


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

Suppose that it would be possible to reduce the visibility. Then look at the following code:

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

class Sub extends Super {
    @Override
    protected void method() {
        // ...
    }
}

Suppose that you would have another class, in another package, where you use these classes:

Super a = new Sub();

// Should this be allowed or not?
a.method();

To check whether a method call is allowed or not, the compiler looks at the type of the variable you call it on. The type of the variable a is Super. But the actual object that a refers to is a Sub, and there the method is protected, so you would say it should not be allowed to call the method from an unrelated class outside the package. To solve this strange situation, it's made forbidden to make overridden methods less visible.

Note that the other way around (making a method more visible) doesn't lead to the same problem.




回答4:


Since Java allows Super class reference to point to sub class object.. So, restriction should not be increased from compile-time to runtime..

Lets see this through an example: -

public class B {
    public void meth() {

    }
}

class A extends B {
    private void meth() {  // Decrease visibility.

    }
}

Now, you create an object of class A and assign it the reference of class B.. Lets see how: -

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

Now, since compiler only checks the type of the reference variable, and check the visibility of methods in that class (class B), and it doesn't check what kind of object does the reference obj refers to.. So, it is not worried about that.. It is left to JVM at runtime to resolve the appropriate method..

But at runtime, JVM will actually try to invoke the meth method of class A as object is of class A.. But, now what happens... BooooOOMM ---> JVM Crashes.. because meth method is private in class A...

That's why visibility is not allowed to be decreased..



来源:https://stackoverflow.com/questions/12780779/why-java-allows-increasing-the-visibility-of-protected-methods-in-child-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!