2013-04-24 40 views

回答

22

的一点是,谁只知道你的主叫用户应该仍然能够使用是它给的任何实例。考虑这种情况:从不同的包

public class Super 
{ 
    public void print() 
    { 
     System.out.println("Hello!"); 
    } 
} 

public class Sub extends Super 
{ 
    @Override 
    void print() // Invalid 
    { 
     System.out.println("Package access"); 
    } 
} 

现在,假设我们有:

public void printSuper(Super x) 
{ 
    x.print(); 
} 

我们叫随:

printSuper(new Sub()); 

你会想到做什么?你覆盖方法,所以它应该打印“包访问” - 但是那意味着你调用从不同的封装包访问方法...

基本上,这是的只是一个例子Liskov Substitution Principle正在进行中。您应该能够将任何子类的实例作为超类的实例对待,并且很难看出它是如何适合于使子类更具限制性的。

+5

您可以引用Liskov替换原则http://en.wikipedia.org/wiki/Liskov_substitution_principle – Scorpion 2013-04-24 06:33:01

+0

如果您不希望用户能够在自己的实现中使用该函数,则始终可以用空白版本覆盖它。这样,类的接口不会中断。当然,你必须决定这种方法是否合理,取决于给定函数的期望。 – Devolus 2013-04-24 06:35:57

+0

@Scorpion:我已经加入了它:) – 2013-04-24 06:39:01

6

您不能使访问修饰符更具限制性,因为这会违反继承的基本规则,即子类实例应该可替换而不是超类实例。

对于例如 假设类具有的getName正在使用由许多类(包括非子类),但有人刚添加雇员作为人的子类,并的getName在公共方法 员工受保护应该只能通过子类访问,那么以前的代码将开始打破,员工将不能替换为Person对象。

因此,java已决定实施这种重构。

1

考虑例如

class Mammal { 
    public Mammal readAndGet() throws IOException {//read file and return Mammal`s object} 
} 

class Human extends Mammal { 
    @Override 
    public Human readAndGet() throws FileNotFoundException {//read file and return Human object} 
} 

下方,如果我们执行下面的代码

Mammal mammal = new Human(); 
Mammal obj = mammal.readAndGet(); 

而且我们知道,编译器mammal.readAndGet()正从Mammal类的对象,但在调用,运行时JVM将解决mammal.readAndGet()方法呼叫来自类Human的呼叫,因为mammal持有new Human()

方法readAndGetMammal定义公共和以使其在Human类的限制较少,我们将需要要么删除访问符(使它default)或使其protectedprivate

现在假设

  • 如果我们定义readAndGetdefaultHumanHumanprotected在另一个包
  • 定义。如果我们在人的定义readAndGet私人

我们知道JVM会在运行时解决方法调用,但编译器不知道这一点,在这两种情况下,公司de会编译成功,因为编译器readAndGet正在从类Mammal中调用。

但在这两种情况下,在运行时JVM将无法从人类获得readAndGet,因为这将限制因Human类的readAndGet严格的访问。

而且我们还不能确定谁将在未来扩展我们的类,以及他将在哪些包中执行该操作,如果该人使重写方法的限制性更小,那么JVM可能无法调用方法和代码将在运行时中断。

所以为了避免这种不确定性,根本不允许在子类中分配对重写方法的限制访问。

还有其他规则,我们需要遵循,同时覆盖的方法,你可以阅读更多的Why We Should Follow Method Overriding Rules知道原因。

相关问题