咱們先來看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的方法。