Java访问修饰符和重写方法
为什么Java指定重写方法的访问说明符可以允许比重写的方法更多(但不less于)的访问? 例如,超类中的受保护实例方法可以在子类中公开,但不是私有的。
这是OOP的基本原则:子类是父类的完全实例,因此必须至less呈现与父类相同的接口。 使受保护的/公共的东西不那么明显会违反这个想法; 您可以使子类作为父类的实例不可用。
想象一下这两个类:
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()是公开的,即使是在狮子私有。 所以不可能在子类中减less显示,因为一旦你有一个超类的引用,你就可以访问这个东西。
因为它会很奇怪:
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!
下面给出一个例子
class Person{ public void display(){ //some operation } } class Employee extends Person{ private void display(){ //some operation } }
典型的重写发生在以下情况
Person p=new Employee();
这里p
是调用p.display()时Persontypes(超类)的对象引用。 由于访问修饰符更具限制性,因此对象引用p
不能访问Employeetypes的子对象
但是我想补充一个与覆盖有关的问题:覆盖的方法必须允许比被覆盖的方法less的(或相同级别的)可抛出的exception; 甚至没有什么可抛弃的。
Liskov替代原则也可以解释:
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,不再(在拍摄地点需要医生)。 所以重写的方法不能打破这个,join更多的DeathException(或者是一辆救护车是必须的)
我经常把这个压倒一切的规则称为“可以更多访问[level],但是更less的例外”
因为子类是超类的专门化,换句话说,它是超类的扩展。
想象一下,例如toString方法。 所有的Java对象都有它,因为类Object具有它。 想象一下你可以使用toString private方法定义一个类。 那么你不再平等地对待所有的对象。 例如,你将无法安全地做到这一点:
for (Object obj : collection) System.out.println(obj);
那么,就你提到的具体情况而言,Java究竟如何处理呢? 如果子类使public / protected方法成为private,那么JVM在子类的实例上调用该方法时应该做什么? 尊敬的私人和调用超类的实现? 而且,当你突然说“没有人可以使用这种方法,不pipe合同最初说了什么”,你就违背了超类规定的合同。