從stackoverflow上的一個問題看Java動態綁定

咱們先來看stackoverflow上的一個問題,先上代碼ide

 1 public class Piece{
 2     public static void main (String [] args){
 3         Piece p2 = new Knight();  
 4         Knight p1 = new Knight();
 5         p1.capture(p2);   
 6         p2.capture(p1);   
 7     }
 8     public void capture(){
 9         System.out.println("Capture");
10     }
11     public void capture(Piece p){
12         System.out.println("I'm bored");
13     }
14 }
15 class Knight extends Piece{
16     public void capture(Piece p){       
17         System.out.println("Knight is bored");
18     }
19     public void capture(Knight k){      
20         System.out.println("Too slow buddy");
21     }
22 }

問的是這段代碼輸出是什麼?答案是學習

Knight is bored
Knight is bored

由於剛剛開始學習Java,在跟CS61B的課,而後老師講到dynamic type和static type的時候,本身有點模糊,因而在stackoverflow上搜索相關的問題,果真發現一個典型的動態綁定的問題,仔細分析以後感受收穫挺大的,對繼承的理解更加深刻了。spa

分析:這個是怎麼回事呢?首先看第三第四行,p1確定是一個Knight類型,而對於p2, 它是一個Piece類型的引用,指向了一個Knight類的對象,此時咱們稱Piece爲static type,而Knight爲dynamic類型。code

p1.capture(p2),也就是Knight.capture(Piece),Knight類裏恰好定義了這個方法,即輸出"Knight is bored"。對象

p2.capture(p1),也就是Piece.capture(Knight),乍一看Piece裏面沒有這個方法啊。這裏應該是有一個賦值,即Piece p = p1,把子類的引用賦給父類,這是容許的。因此實際上調用的Piece.capture(Piece),那麼結果應該輸出"I'm bored"啊,怎麼會是"Knight is bored"呢?前面已經說了,p2實際上指向了一個Knight類的對象,而在Knight類中恰好Ovriride了這個Piece.capture(Piece)方法,也就是Knight.capture(Piece),因此應該調用這個方法,即輸出"Knight is bored"。blog

 

好如今咱們把這個Override的方法註釋掉,看看結果如何?繼承

 1 public class Piece{
 2     public static void main (String [] args){
 3         Piece p2 = new Knight();  //static Piece, dynamic Knight
 4         Knight p1 = new Knight();
 5         p1.capture(p2);   
 6         p2.capture(p1);   
 7     }
 8     public void capture(){
 9         System.out.println("Capture");
10     }
11     public void capture(Piece p){
12         System.out.println("I'm bored");
13     }
14 }
15 class Knight extends Piece{
16     // public void capture(Piece p){       //這裏override了Piece中的方法
17     //     System.out.println("Knight is bored");
18     // }
19     public void capture(Knight k){      
20         System.out.println("Too slow buddy");
21     }
22 }

輸出結果是:class

I'm bored
I'm bored

分析:第二個輸出剛剛已經解釋了,由於如今沒有override的方法了,因此就直接調用Piece類中的Piece.capture(Piece p)方法。那麼第一個輸出又是怎麼回事呢?p1.capture(p2),也就是Knight.capture(Piece),這裏不能調用Knight.capture(Knight k)這個方法,由於Knight k = p2,這是不合法的,Java中不容許把父類的引用賦給子類的引用變量。那麼既然如此,Knight類中豈不是沒有這個方法了嗎?不要忘記,Knight類是繼承在Piece類上的,也就是Knight類型也能調用Piece類中的方法,也就是Piece.capture(Piece)方法,因此輸出是"I'm bored"。變量

 

如今咱們知道,Piece p2 = new Knight()這句特殊之處就在於,有一個查找在子類中是否存在override的方法,若是存在就調用子類中這個override的方法,若是沒有就使用父類中的方法。若是是這樣定義的:Piece p2 = new Piece(),那麼不管在子類中有沒有override方法,都不會去調用子類的方法,而是直接調用父類的方法。以下:搜索

 1 public class Piece{
 2     public static void main (String [] args){
 3         // Piece p2 = new Knight();  //static Piece, dynamic Knight
 4         Piece p2 = new Piece();
 5         Knight p1 = new Knight();
 6         p1.capture(p2);   
 7         p2.capture(p1);   
 8     }
 9     public void capture(){
10         System.out.println("Capture");
11     }
12     public void capture(Piece p){
13         System.out.println("I'm bored");
14     }
15     public void capture(Knight p){
16         System.out.println("Hello");
17     }
18 }
19 class Knight extends Piece{
20     public void capture(Piece p){       //這裏override了Piece中的方法
21         System.out.println("Knight is bored");
22     }
23     public void capture(Knight k){      //這裏override了Piece中的方法
24         System.out.println("Too slow buddy");
25     }
26 }

輸出結果是:

Knight is bored
Hello

咱們能夠看到,即便在Knight類中override了.capture(Knight)方法,因爲p2一直就是一個Piece類,根本不會調用Knight類中的方法,因此p2.capture(p1),也就是Piece.capture(Knight),輸出"Hello"。第四行改爲Piece p2 = new Knight(),則輸出就是:

Knight is bored
Too slow buddy

第二個輸出調用的就是Knight類中override的方法。

相關文章
相關標籤/搜索