2011-03-05 75 views

回答

10

我会尝试将其他答案的想法纳入到单个答案中。

首先,让我们来看看代码中发生了什么。

一看代码

One类有一个包私人foo方法:

class One { 
    // The lack of an access modifier means the method is package-private. 
    void foo() { } 
} 

Two类的子类的One类和foo方法重写,但有访问修饰符private

class Two extends One { 
    // The "private" modifier is added in this class. 
    private void foo() { /* more code here */ } 
} 

问题

Java语言不允许子类,以减少在子类中的方法,字段或类的可见性,因此,Two类减少foo方法的能见度不合法。

为什么要降低可见性是一个问题?

考虑我们要使用的One类情况:

class AnotherClass { 
    public void someMethod() { 
    One obj = new One(); 
    obj.foo(); // This is perfectly valid. 
    } 
} 

这里,调用foo方法上One实例有效。 (假设AnotherClass类在同一个包中One类)。

现在,如果我们是来实例化对象Two,并将其放置在型Oneobj变量?

class AnotherClass { 
    public void someMethod() { 
    One obj = new Two(); 
    obj.foo(); // Wait a second, here... 
    } 
} 

Two.foo方法是私有的,然而,One.foo方法将允许访问方法。我们在这里遇到了问题。

因此,考虑继承时允许降低可见性没有多大意义。

链接

+0

+1作为写过其他答案之一的人,这是一篇很好的总结,写得很好。感谢您将它们放在一起! – templatetypedef

+0

非常精确,重点突出。 –

1

此代码的问题在于,如果它是合法的,那么如果您通过One基类间接访问它,Java将无法尊重private修饰符foo。例如,如果我写

One obj = new Two(); 
obj.foo(); 

那么我们就会有麻烦,因为我们会被调用private方法Twofoo间接,当编译器检查它着眼于One以确定线路obj.foo()自如果foo可访问,则不在Two。这样做的原因是,编译器不能总是分不清什么obj可以在被人指指点点 - 如果,例如,我喜欢写东西

One obj = Math.random() < 0.5? new One() : new Two(); 
obj.foo(); 

那么编译器无法知道是否在Oneobj点或一个Two。因此,在检查访问说明符时,它会遵循One。如果我们确实允许在Two中标记foo private,那么编译器会错误地允许我们通过obj(它的类型为One)调用它,绕过保证只有对象本身可以调用private方法。

+0

真正的问题是在Java中不允许降低可见性。即使第一个方法被保护,第二个包为私有,编译器也可以编译,但是不允许声明。 – bestsss

+0

@ bestsss-是的,这是真的,但这个决定背后的推理是对上述逻辑的扩展。 – templatetypedef

0

它会破坏多态性。

如果你有一个Two实例存储在一个Two变量中,那么foo不能被调用是有意义的。但是,如果您将One实例存储在One变量中,那么您只知道One。但是,一个人拥有公共福利,这可以被称为。这将是一个不一致,而且会很奇怪。

0

因为继承是的关系。任何人都可以通过参考指的Two一个实例One

One v = new Two(); 

什么会的程序做,如果你呼吁V基准foo的方法是什么?你打破了One的公共契约,保证One的每个实例都有一个(这里是封装保护的)foo方法。这就是编译器禁止它的原因。

1

给出的答案给你技术上的解释,为什么你不能一个接一个的扩展。我想给你一个理解,为什么这是不可能的,因为面向对象的模式,而不是由于语言本身。

通常,第一类是带有其访问器的类的一般定义,即方法到外部世界。扩展这个类的子类必须为外部世界提供相同的访问者。两个在你的例子中扩展一个,这意味着,Two提供了和One一样的外部世界的访问器。如果您要更改One的访问器的可见性,则外部世界将无法再访问您的类,因为它们习惯使用类型为One的对象进行访问。

相关问题