为什么我们不能在子类中分配较弱的权限

sya*_*yam 12 java inheritance

我有一个类,它有一个方法,默认情况下访问说明符是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应用程序中的主要错误来源.这里讨论的语言限制避免了这个令人讨厌的问题.


Pet*_*rey 8

您无法限制访问权限,因为您已在超类中允许更多访问权限.例如

SuperClass sc = new SubClass();
sc.foo(); // is package local, not private.
Run Code Online (Sandbox Code Playgroud)

访问sc的类型由引用的类型而sc不是它引用的内容决定,因为编译器不可能在所有情况下都知道对象在运行时的类型.为了这是一个安全的假设,子类必须遵守父类给出的合同,否则它不能成为有效的子类.这与父母说实现方法但子类说它不是(或不可访问)没有什么不同

您可以通过说您只能通过父级访问子类方法来解决此问题,而不是直接访问.这个问题是你不知道父母何时可以添加一个方法,当你创建一个方法时,private你要这样做是因为你希望它是私有的,而不是另一种方式.

BTW您仍然可以通过反射访问私有方法,这会产生副作用,导致JVM出现各种问题.例如,它必须保留私有方法,即使它可能确定无法正常调用它.

简而言之,您希望代码表示它所说的内容,而不是具有分裂的个性.它既可以是本地包,也可以是私有的,而不是介于两者之间但不是真的.从另一个角度来看,这不是一个问题.即如果子类是公共的.它只是意味着子类可以在比父级更多的地方使用,就像它可以实现更多的方法一样.

  • 是的,但为什么一定是(他在问什么)? (4认同)

Vik*_*s V 6

如果允许这样做,就会有一个后门,通过它可以调用不应该访问的方法.

让我们说这是允许的

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中的方法的调用,请设置此限制.