我有一个类,它有一个方法,默认情况下访问说明符是public.现在,我想在子类中扩展此类,并且我想覆盖此方法以使访问说明符为"private".编译此代码时,我收到编译错误:
"尝试分配较弱的访问权限".
有人可以向我解释在子类中分配较弱的权限有什么问题吗?
以下是导致编译错误的代码:
class Superclass
{
void foo()
{
System.out.println("Superclass.foo");
}
}
class Subclass extends Superclass
{
private void foo()
{
System.out.println("Subclass.foo");
}
}
Run Code Online (Sandbox Code Playgroud)
Ste*_*n C 28
简短的回答是不允许这样做,因为它会破坏类型的可替代性; 另见Liskov替代原则(LSP).
关键是Java(和其他编程语言)中的多态性依赖于您能够将子类的实例视为超类的实例.但是如果该方法在子类中受到限制,您会发现编译器无法确定访问规则是否允许调用方法...
例如,假设您的示例代码是合法的:
// Assume this code is in some other class ...
SuperClass s1 = new SuperClass();
s1.foo(); // OK!
SuperClass s2 = new Subclass();
s2.foo(); // What happens now?
SuperClass s3 = OtherClass.someMethod();
s3.foo(); // What happens now?
Run Code Online (Sandbox Code Playgroud)
如果你决定是否s2.foo()允许声明的类型s2,那么你允许private从抽象边界之外调用方法Subclass.
如果您根据s2引用的对象的实际类型做出决定,则无法静态执行访问检查.的s3情况下,使这个更加明显.编译器绝对无法知道返回的对象的实际类型是什么someMethod.
可能导致运行时异常的访问检查将成为Java应用程序中的主要错误来源.这里讨论的语言限制避免了这个令人讨厌的问题.
您无法限制访问权限,因为您已在超类中允许更多访问权限.例如
SuperClass sc = new SubClass();
sc.foo(); // is package local, not private.
Run Code Online (Sandbox Code Playgroud)
访问sc的类型由引用的类型而sc不是它引用的内容决定,因为编译器不可能在所有情况下都知道对象在运行时的类型.为了这是一个安全的假设,子类必须遵守父类给出的合同,否则它不能成为有效的子类.这与父母说实现方法但子类说它不是(或不可访问)没有什么不同
您可以通过说您只能通过父级访问子类方法来解决此问题,而不是直接访问.这个问题是你不知道父母何时可以添加一个方法,当你创建一个方法时,private你要这样做是因为你希望它是私有的,而不是另一种方式.
BTW您仍然可以通过反射访问私有方法,这会产生副作用,导致JVM出现各种问题.例如,它必须保留私有方法,即使它可能确定无法正常调用它.
简而言之,您希望代码表示它所说的内容,而不是具有分裂的个性.它既可以是本地包,也可以是私有的,而不是介于两者之间但不是真的.从另一个角度来看,这不是一个问题.即如果子类是公共的.它只是意味着子类可以在比父级更多的地方使用,就像它可以实现更多的方法一样.
如果允许这样做,就会有一个后门,通过它可以调用不应该访问的方法.
让我们说这是允许的
class Super {
public void method() {
System.out.println("Super");
}
}
class Sub extends Super {
// This is not allowed, but suppose it was allowed
protected void method() {
System.out.println("Sub");
}
}
// In another class, in another package:
Super obj = new Sub();
obj.method();
Run Code Online (Sandbox Code Playgroud)
obj.method 将是可能的,因为method()是public在超类.但是它不应该被允许,因为obj实际上是指Sub的一个实例,并且在该类中,该方法受到保护!
要限制对不能从外部访问的类Sub中的方法的调用,请设置此限制.