标签:
我们先来看stackoverflow上的一个问题,先上代码
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上搜索相关的问题,果然发现一个典型的动态绑定的问题,仔细分析之后感觉收获挺大的,对继承的理解更加深入了。
分析:这个是怎么回事呢?首先看第三第四行,p1肯定是一个Knight类型,而对于p2, 它是一个Piece类型的引用,指向了一个Knight类的对象,此时我们称Piece为static type,而Knight为dynamic类型。
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"。
好现在我们把这个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 }
输出结果是:
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的方法。
标签:
原文地址:http://www.cnblogs.com/ttylcc/p/5475822.html