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


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

为什么我们不能降低能见度,但可以提高能见度?

此外,我还需要实现Template模式,其中可见的公共方法只能是基类的。

示例:

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允许提高可见性,那么有两种方法是公开可见的??

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

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

但是,为什么允许它增加方法的可见性呢?首先,它不会破坏任何契约,所以没有理由不允许它。当在子类中不保护方法有意义时,它有时会很方便。

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

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

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

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

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

为什么我们不能降低可见性,但可以提高可见性?

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

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,所以您会说不应该允许它从包外的不相关类调用方法。为了解决这种奇怪的情况,禁止减少重写方法的可见性。

请注意,另一种方法(使方法更可见)不会导致同样的问题。

由于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实际上会尝试调用类Ameth方法,因为对象属于类A。但是,现在发生了什么BooooOOMM--->JVM崩溃。。因为meth方法在class A中是私有的。。。

这就是为什么能见度不允许降低的原因。。

最新更新