覆盖方法时,为什么我可以增加访问但不减少访问?

时间:2011-07-27 21:44:35

标签: java inheritance access-modifiers

为什么Java指定覆盖方法的访问说明符可以允许比重写方法更多但不是更少的访问?例如,超类中的受保护实例方法可以在子类中公开,但不是私有的。

8 个答案:

答案 0 :(得分:62)

这是OOP中的一个基本原则:子类是父类的完全成熟实例,因此必须提供至少与父类相同的接口。使受保护/公共事物不那么明显会违反这一想法;您可以将子类作为父类的实例使用。

答案 1 :(得分:32)

想象一下这两个类:

public class Animal {
  public String getName() { return this.name; }
}

public class Lion extends Animal {
  private String getName() { return this.name; }
}

我可以写下这段代码:

Animal lion = new Lion();
System.out.println( lion.getName() );

它必须是有效的,因为在动物方法 getName()是公开的,即使它在 Lion 。所以不可能在子类上使事情变得不那么明显,因为一旦有了超类引用,就可以访问这些东西了。

答案 2 :(得分:8)

举一个例子

 class Person{
 public void display(){
      //some operation
    }
 }

class Employee extends Person{
   private void display(){
       //some operation
   }
 }

典型的覆盖发生在以下情况

Person p=new Employee();

这里p是我们调用时类型为Person(超类)的对象引用 的 p.display()即可。由于访问修饰符限制性更强,对象引用p 无法访问类型为Employee的子对象

答案 3 :(得分:7)

因为它会很奇怪:

class A {
    public void blah() {}
}

class B extends A {
    private void blah() {}
}


B b = new B();
A a = b;
b.blah();  // Can't do it!
a.blah();  // Can do it, even though it's the same object!

答案 4 :(得分:3)

晚会但我想补充一个与覆盖相关的问题:覆盖方法必须允许比重写方法更少(或相同级别)的throwable异常;甚至根本没什么可扔的。

利斯科夫替代原则也可以解释这一点:

interface Actionable {
  void action() throws DislocationException;
}

public class Actor implements Actionable {
  @Override 
  public void action() throws DislocationException {
     //....
  }
} 

public class Stuntman implements Actionable {
  @Override // this will cause compiler error
  public void action() throws DislocationException, DeathException {
     //....
  }
}

// legacy code to use Actionable
try {
   Actionable actor = new Actor(); // this cannot be replaced by a Stuntman, 
                                   // or it may break the try/catch block
   actor.action();
} catch (DislocationException exc) {
   // Do something else
}

上面,被覆盖的方法做出了承诺,在最坏的情况下,它将抛出DislocationException,不再需要(在拍摄地点需要医生)。因此,重写方法不能破坏它,通过添加更多DeathException(或救护车是必须的)

我经常称之为最重要的规则" [可以]更多访问[级别],[但]少例外"

答案 5 :(得分:0)

因为子类是超类的特化,换句话说,它是超类的扩展。

想象一下例如toString方法。所有Java对象都拥有它,因为Object类具有它。想象一下,您可以使用toString private方法定义一个类。然后,您不再平等对待所有对象。例如,您将无法再安全地使用此功能:

for (Object obj : collection) System.out.println(obj);

答案 6 :(得分:0)

那么,就你提到的具体情况而言,Java究竟会如何处理呢?如果子类将public / protected方法设为private,那么当在子类的实例上调用该方法时,JVM应该怎么做?尊重私人并调用超级班级'实施?此外,当你突然说'#34;没有人可以访问这种方法时,你会违反超类规定的合同,尽管合同最初说的是什么。"

答案 7 :(得分:0)

要重新说明已经说过的话,这与将Java编译成字节码然后由JVM解释有关。当子类覆盖其父方法之一时,编译器将使用引用类型来确定要使用两种方法中的哪一种。然后,JVM在运行时使用对象类型来确定应真正使用的方法。

在上面的示例中; Animal lion = new Lion(),当调用lion.getName()时,编译器使用该方法的Animal版本,并且JVM替换它/可以将其替换为Lion版本,因为它“完全适合”。但是,如果允许Lion对getName()的限制比对Animal的getName()的限制更多,那么您可以绕开该限制,因为如果Lion对象具有Animal引用,则编译器会将其视为不受限制。

为解决此问题,java规定,使子对象使覆盖方法比其覆盖方法受到更多限制是非法的。