为什么Java允许增加子类中受保护方法的可见性?
为什么我们不能降低能见度,但可以提高能见度 我还需要实现模板模式,其中可见的公共方法只能是基类 例如:为什么Java允许增加子类中受保护方法的可见性?,java,design-patterns,Java,Design Patterns,为什么我们不能降低能见度,但可以提高能见度 我还需要实现模板模式,其中可见的公共方法只能是基类 例如: abstract class Base{ protected abstract void a(); } class Child extends Base{ @Override public void a(){ //why is this valid } } 现在,如果java允许增加可见性,那么有两种方法是公开可见的 我知
abstract class Base{
protected abstract void a();
}
class Child extends Base{
@Override
public void a(){
//why is this valid
}
}
现在,如果java允许增加可见性,那么有两种方法是公开可见的
我知道接口是一种解决方案,但是还有其他的解决方法吗?如果基类做出了关于可见性的承诺,那么子类就不能违背这个承诺,并且仍然满足Liskov替换原则。在任何情况下都不能使用子类,如果承诺被破坏,那么承诺的方法就会被暴露 子类是一个基类。如果基类公开方法,那么子类也必须公开方法
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
}
}
假设您在另一个包中有另一个类,您在其中使用这些类:
class Super {
public void method() {
// ...
}
}
class Sub extends Super {
@Override
protected void method() {
// ...
}
}
为了检查是否允许方法调用,编译器会查看调用它的变量的类型。变量a
的类型为Super
。但是a
引用的实际对象是Sub
,并且该方法受保护
,因此您可以说不允许它从包外的不相关类调用该方法。为了解决这种奇怪的情况,禁止使重写的方法变得不可见
请注意,另一种方法(使方法更可见)不会导致相同的问题。因为Java允许超类引用指向子类对象。。因此,限制不应该从
编译时
增加到运行时
让我们通过一个例子来了解这一点:-
Super a = new Sub();
// Should this be allowed or not?
a.method();
现在,创建一个类A
的对象,并将其指定为类B
的引用。。
让我们看看如何:-
public class B {
public void meth() {
}
}
class A extends B {
private void meth() { // Decrease visibility.
}
}
现在,由于编译器
只检查引用变量的类型,并检查该类(类B)中方法的可见性,而它不检查引用的对象是指什么类型的对象。。所以,它并不担心。。由JVM在运行时解析适当的方法
但是在运行时,JVM实际上会尝试调用类A
的meth
方法,因为对象属于类A。。但是,现在发生了什么BOOOOOMM-->JVM崩溃。。因为meth
方法在A类中是私有的
这就是为什么不允许降低可见性。其他响应中已经解释了为什么不允许降低可见性(这将破坏父类的契约)
但是为什么允许它增加方法的可见性呢?首先,它不会违反任何合同,因此没有理由不允许它。当一个方法在子类中不受保护是有意义的时候,它有时会很方便
其次,不允许这样做可能会产生副作用,即有时无法扩展类并同时实现接口:
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..
关于你的第二个问题,你无能为力。您必须相信实现子类的人不会做任何破坏您的实现的事情。即使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.
}
我没有完全得到答案??所以你是说我不能限制子类以任何方式增加可见性??每个问题一个问号就可以了。我认为“不”应该很容易理解。不能使方法在子对象中的可见程度低于在父对象中的可见程度。让编译器告诉你答案。总比到这儿来问我好。请原谅我的问号。但是你能帮我写第二个例子吗?问题是什么?子级可以选择使方法比其父级更可见,但不能使其不可见。它仍然使利斯科夫满意;它仍然是——一位家长;您可以在调用父方法a()的任何上下文中调用更可见的子方法a()。是的,我现在理解了这个原理。但我能做些什么来强制执行基类方法,这是我的实际问题!看我的第二个例子,我现在明白了,谢谢。但是你能帮我解决模板方法的问题吗?我需要在基类中做一些重要的事情,如果有两个方法是公开的,那么我不能在基类中保持控制?从语义上讲,允许子类隐藏父类成员是没有问题的。接收迭代器的代码可以对其调用remove
,因为调用方可能只传递支持该方法的迭代器;但是,如果允许接收对不可变集合迭代器实现的强类型引用的代码对其调用remove
,则不会得到任何好处,因为该操作不可能工作。允许私有
重写的危险在于子类可能打算创建私有函数,而不是重写公共函数。谢谢Pablo。这就是我所寻找的,一个允许增加可见性的有效论点。@NP_JavaGeek如果这是你所寻找的答案,你应该接受它(正如解释的那样)想想克隆方法。它是受保护的,但您应该将其设置为受保护或public。还有第三个很好的理由,子类总是可以使用另一个公开方法,间接地公开受保护的功能。因此,任何不允许它的企图都是站不住脚的
class Child extends Base{
@Override
protected void a(){
}
public void a2() {
a(); //This would have the same problems that allowing to increase the visibility.
}
}