在扩展类时,既可以向类中添加新的成员,也可以重新定义现有的成员。重定义现有成员的具体效果取决于成员的类型。本文不会详细的介绍概念,只简要总结覆盖(overriding,也叫重写)和隐藏(hiding)中最关键的地方。
方法覆盖的条件
概念:一个方法将方法的超类实现替换为自己的实现。覆盖并不要求两个方法类型完全一致,具体要求总结如下:
- 签名: 覆盖方法的签名必须与超类相同,签名即为方法名和参数类型列表。
- 返回类型: 覆盖方法返回类型可以是超类方法返回类型的子类型。
- 访问权限: 覆盖方法可以改变访问修饰符,但只能提供更多的访问权限。
- 异常: 覆盖方法抛出的异常可以比超类少,也可以是其子类型。
这些要求的规律就是覆盖的方法必须要与超类方法兼容,因为这样可以保证重写之后超类方法的契约仍然成立。
继承成员的访问
调用哪个(非静态)方法是由对象的实际类型决定的,访问哪个字段是由引用的类型决定的。参考如下示例:
class SuperShow {
public String str = "SuperStr";
public void show() {
System.out.println("Super.show: " + str);
}
}
class ExtendShow extends SuperShow {
public String str = "ExtendStr";
public void show() {
System.out.println("Extend.show: " + str);
}
public static void main(String[] args) {
ExtendShow ext = new ExtendShow();
SuperShow sup = ext;
sup.show();
ext.show();
System.out.println("sup.str = " + sup.str);
System.out.println("ext.str = " + ext.str);
}
}
输出结果如下:
$ java ExtendShow
Extend.show: ExtendStr
Extend.show: ExtendStr
sup.str = SuperStr
ext.str = ExtendStr
根据之前所说的规则,show
方法的调用总是会到ExtendShow
类的版本上,这是由对象的实际类型决定的。而str
的访问则是由引用决定,具体访问哪一个字段在编译期基于引用的类型决定。