问题的提出:
class Parent {
private void method1() {
System.out.println("Parent's method1()");
}
public void method2() {
System.out.println("Parent's method2()");
method1(); // ①
}
}
class Child extends Parent {
public void method1() {
System.out.println("Child's method1()");
}
public static void main(String args[]){
Parent p = new Child(); // ②
p.method2(); // ③
}
}
在②处声明了一个Parent类型的引用p,它指向一个Child对象;通常来说,p应该具有后绑定功能。③处调用method2(),这个method2()肯定是指从Parent类继承而来的method2()。
但问题是Parent类的method2()中,调用了method1(),这个method1()是谁的?Parent的,还是Child的?
看起来挺难判断的,但结果是调用了Parent的method1()?也许会问method1()不是Parent的一个私有成员吗?Child对象怎么能调用呢?
请先看下面的例子,将得到解答——
例子一:
class Base5 {
protected void doStuff1() {
System.out.println("Base-doStuff1");
}
final void doStuff2() {
System.out.println("Base-doStuff2");
}
}
class Child5 extends Base5 {
protected void doStuff1() {
System.out.println("Child-doStuff1");
}
protected void doStuff2() { // ④
System.out.println("Child-doStuff2");
}
public static void main(String[] args) {
Base5 c = new Child5();
c.doStuff1();
c.doStuff2();
}
}
编译结果如下:
D:/JavaEx/scjp/tst/tst18.java:14: doStuff2() in Child5 cannot override doStuff2() in Base5; overridden method is final
protected void doStuff2() {
^
1 error
由于Base5的doStuff2()是final的,所以④处Child5无法重写doStuff2(),因此也就不会有后绑定的多态。亦即:父类中final的方法不支持后绑定的多态。
例子二:
class Base5 {
protected void doStuff1() {
System.out.println("Base-doStuff1");
}
private void doStuff2() {
System.out.println("Base-doStuff2");
}
}
class Child5 extends Base5 {
protected void doStuff1() {
System.out.println("Child-doStuff1");
}
protected void doStuff2() {
System.out.println("Child-doStuff2");
}
public static void main(String[] args) {
Base5 c = new Child5();
c.doStuff1();
c.doStuff2();
}
}
编译结果如下:
D:/JavaEx/scjp/tst/tst18.java:21: doStuff2() has private access in Base5
c.doStuff2();
^
1 error
因为是私有成员,所以c.doStuff2()会产生错误,但更重要的是private就相当于final,父类中的final方法不支持后绑定,则private也是如此。亦即:父类中private的方法不支持后绑定的多态。
只有一步之遥
离解答问题只有一步之遥,还得补充一个基本常识。类的成员方法不论是否接受参数,它其实都隐含地接受了一个参数,即this。
何谓this?由《Thinking in Java(3rd Edition)》中:this是对当前对象的一个引用。
回到最初的问题:
class Parent {
private void method1() {
System.out.println("Parent's method1()");
}
public void method2() {
System.out.println("Parent's method2()");
method1(); // ⑤
}
}
class Child extends Parent {
public void method1() {
System.out.println("Child's method1()");
}
public static void main(String args[]){
Parent p = new Child();
p.method2();
}
}
由上一段补充的知识可知⑤处实际上是:
this.method1();
根据例子一和二可知,父类中private的方法不支持后绑定多态,因此它严格按照引用的类型来调用对应的方法,因此它调用Parent的method1()。
当把Parent的method1()前的private换成public/protected/friendly(默认),则后绑定将顺利完成,自动调用Child的method1()。
总结
父类中final的方法在子类中无法被重写,因此不会有后绑定多态的问题。
父类中private的方法类似于final,虽然可以被重新定义,但不是重写。
当出现父类中含有private的方法的后绑定多态问题时,非private方法依然可以根据后绑定对象的实际情况,实时调用对应的方法;而private的方法,不支持此特性,它只根据调用它的引用类型来确定需要调用的方法。