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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12780779/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 10:11:18  来源:igfitidea点击:

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

javadesign-patterns

提问by Narendra Pathai

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 patternin 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??

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

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

我知道接口是一种解决方案,但还有其他出路吗???

回答by Pablo

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:

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

回答by duffymo

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.

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

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

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

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

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

回答by Jesper

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 ais Super. But the actual object that arefers 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.

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

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

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

回答by Rohit Jain

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

由于Java允许超类引用指向子类对象。所以,限制不应该从增加compile-timeruntime..

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 Aand assign it the reference of class B.. Lets see how: -

现在,您创建一个 class 对象A并将其分配给 class 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..

Now, since compileronly 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 objectdoes the referenceobj refers to.. So, it is not worried about that.. It is left to JVM at runtime to resolve the appropriate method..

现在,由于compiler只检查引用变量的类型,检查的方法,在该类知名度(B类),并且它不检查什么样的对象呢的referenceOBJ指..所以,它不担心那.. 在运行时留给 JVM 来解析适当的方法..

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

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

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

这就是为什么不能降低能见度的原因..