为什么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允许增加可见性,那么有两种方法可以公开显示?
我知道界面是一个解决方案,但还有其他方法吗?
为什么不允许降低可见性已在其他响应中解释(它将破坏父类的合同)。
但为什么允许它增加方法的可见性? 首先,它不会破坏任何合同,因此没有理由不允许它。 有时,它可以很方便,当在子类中有意义的方法不受保护时。
其次,不允许它可能产生副作用,有时无法扩展类并同时实现接口:
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替换原则。 如果承诺被破坏,则不能在承诺方法公开的任何情况下使用子类。
子类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类)中方法的可见性,并且它不检查 reference
obj所reference
的对象类型 。所以,它不是担心这个问题。它在运行时留给JVM来解决相应的方法。
但是在运行时 ,JVM实际上会尝试调用类A
的meth
方法,因为对象是A类。但是,现在发生了什么…… BooooOOMM —> JVM崩溃 ..因为在方法class A
meth
方法是私有class A
。 ..
这就是为什么不允许降低能见度的原因。