为什么Java不限制子类的可见性大于父类
为什么您可以在Java中创建一个子类,其可见性低于超类为什么Java不限制子类的可见性大于父类,java,polymorphism,package,public,overriding,Java,Polymorphism,Package,Public,Overriding,为什么您可以在Java中创建一个子类,其可见性低于超类 package 1 public class Class1 { public Class1 hello(){ Class1 c= new Class2(); return c; } } class Class2 extends Class1 { public Class1 hello() { System.out.println("In override
package 1
public class Class1 {
public Class1 hello(){
Class1 c= new Class2();
return c;
}
}
class Class2 extends Class1 {
public Class1 hello() {
System.out.println("In overriden method");
return null;
}
}
假设Class1和Class2都在同一个包中,Class2可见性是包私有的
package 2
public class Major {
public static void main(String[] args) {
Class1 ob = new Class1();
ob.hello().hello();
}
}
您将注意到,由于运行时多态性,将打印“In-overrided方法”
在运行期间,当Class2
位于具有包私有可见性的不同包中时,如何从main()
访问hello()
方法
Class2
不应被访问,因此Class2
中的hello(
)方法也不应被访问。protected关键字(某种程度上类似于package private)是一种保护代码不被外部使用的方法,这正是您的示例中发生的情况。您不是直接使用Class2
,而是使用Class1
,它授予您间接使用受保护的Class2
的权利
这是一项责任原则public Class1
负责授权外部包使用受保护的Class2。但这一责任也意味着Class1
的开发人员必须知道为什么以及如何授予您这一权利
在您的示例中,
extend Class1
这一事实没有实际意义,您的困惑可能来自于此。您不能从包外部实例化Class2
,但Class1
可以。protected关键字(某种程度上类似于package private)是一种保护代码不被外部使用的方法,这正是您的示例中发生的情况。您不是直接使用Class2
,而是使用Class1
,它授予您间接使用受保护的Class2
的权利
这是一项责任原则public Class1
负责授权外部包使用受保护的Class2。但这一责任也意味着Class1
的开发人员必须知道为什么以及如何授予您这一权利
在您的示例中,
extend Class1
这一事实没有实际意义,您的困惑可能来自于此。您不能从包外实例化Class2
,但Class1
可以。实际上,考虑到所涉及方法的类型签名,它可能无法以任何其他方式工作
Class1
声明一个名为hello
的方法,返回Class1
的对象。因此,从该方法返回的内容必须实现与Class1
兼容的接口。当Class1.hello()
返回Class2
的实例时,调用者与该实例的交互方式不应与Class1
的实例不同-这是实际的-关键的面向对象原则之一
如果Class2.hello()
由于Class2
被隐藏而变得不可访问,那么调用者将不得不面对这样一个事实,即他们不知道Class1.hello()将返回什么类型的对象
-有时它可能是Class2
的对象,有时它可能是Class1
的对象,或者可以从Class1
扩展的任何其他对象,知道的唯一方法是检查代码-即知道Class1
的实现细节。在这种情况下,编译器将无法保证类型安全,因为Class1.hello()
原则上可能是不可判定的或依赖于运行时状态。在一种静态类型的语言中,这几乎是游戏结束了
以某种方式隐藏一个类—通过将其创建为私有类型、匿名实现接口、通过反射欺骗等—只会隐藏类型本身,而不会隐藏它所实现的接口。通过扩展另一个类,任何给定类型都会自动继承父类型的接口,包括其可见性。扩展类型只允许增加接口的可见性,而不是降低它,否则就违反了Liskov替换原则。实际上,考虑到所涉及方法的类型签名,它可能无法以任何其他方式工作
Class1
声明一个名为hello
的方法,返回Class1
的对象。因此,从该方法返回的内容必须实现与Class1
兼容的接口。当Class1.hello()
返回Class2
的实例时,调用者与该实例的交互方式不应与Class1
的实例不同-这是实际的-关键的面向对象原则之一
如果Class2.hello()
由于Class2
被隐藏而变得不可访问,那么调用者将不得不面对这样一个事实,即他们不知道Class1.hello()将返回什么类型的对象
-有时它可能是Class2
的对象,有时它可能是Class1
的对象,或者可以从Class1
扩展的任何其他对象,知道的唯一方法是检查代码-即知道Class1
的实现细节。在这种情况下,编译器将无法保证类型安全,因为Class1.hello()
原则上可能是不可判定的或依赖于运行时状态。在一种静态类型的语言中,这几乎是游戏结束了
以某种方式隐藏一个类—通过将其创建为私有类型、匿名实现接口、通过反射欺骗等—只会隐藏类型本身,而不会隐藏内部