Java为什么要指定覆盖方法的访问说明符可以比覆盖方法允许更多但不能更少的访问?例如,超类中的受保护实例方法可以在子类中公开,但不能私有。
Java为什么要指定覆盖方法的访问说明符可以比覆盖方法允许更多但不能更少的访问?例如,超类中的受保护实例方法可以在子类中公开,但不能私有。
Answers:
这是OOP中的基本原则:子类是父类的完整实例,因此必须至少提供与父类相同的接口。使受保护的/公共的东西不那么明显将违反这个想法;您可以使子类无法用作父类的实例。
想象一下这两个类:
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() );
而且它必须是有效的,因为在Animal上,getName()方法是公共的,即使它在Lion上是私有的。因此,不可能使事情在子类上不那么显眼,因为一旦有了超类引用,您就可以访问这些东西。
举一个下面给出的例子
class Person{
public void display(){
//some operation
}
}
class Employee extends Person{
private void display(){
//some operation
}
}
在以下情况下会发生典型的覆盖
Person p=new Employee();
这p
是我们调用p.display()时类型为Person(super class)的对象引用
。由于访问修饰符的限制更严格,因此对象引用p
无法访问Employee类型的子对象
迟到了,但我想添加一个与覆盖有关的更多问题:覆盖方法必须比覆盖方法允许更少(或相同级别的)可抛出异常;甚至什么都没有抛出。
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(在拍摄位置需要医生)。因此,重写方法一定不能通过添加更多DeathException来打破这一点(否则必须使用救护车)
我经常将最重要的规则称为“ [可以]在[级别]上有更多的访问权限,但在[例外]上有较少的例外”
要改写已经说过的话,这与Java如何编译成字节码然后由JVM解释有关。当子类覆盖其父方法之一时,编译器将使用引用类型来确定要使用两种方法中的哪一种。然后,JVM在运行时使用对象类型来确定应真正使用的方法。
在上面的示例中;Animal lion = new Lion()
, 什么时候lion.getName()
被调用时,编译器使用该方法的Animal版本,并且JVM替换它/可以将其替换为Lion版本,因为它完全“适合”。但是,如果允许Lion对getName()的限制比对Animal的getName()的限制要大,那么您可以绕开该限制,因为如果Lion对象具有Animal引用,则编译器会将其视为不受限制。
为了解决这个问题,java规定孩子对覆盖的方法进行比对其覆盖的方法更严格的限制是非法的。
B extends A
ifB is-a A
。因此,如果A
可以做action()
和B is-a A
,那么B
应该也可以做action()
。