老师今天在讨论群里抛出了一个问题,让大家尝试思考一下他所给的一段代码输出是什么。
其代码如下:
class T { void foo() { this.bar(); } void bar() { System.out.println("T.bar"); } public static void main(String args[]) { B b = new B(); b.foo(); } } class B extends T { void foo() { super.foo(); } void bar() { System.out.println("B.bar"); } }
思考了一波:
实例化子类对象,子类父类都没有显式构造器,就是在子类父类方法之间跳来跳去的。
“嗯,答案一定是'T.bar'”。
但还是敲了一遍,发现答案竟然是'B.bar'......(如图)
室友说:“对啊,this不就是指向当前对象嘛...”
(啪,打脸...疼...)
重新审视了一遍,才发现自己对于this还是没理解到位...
也就是说,整段代码执行流程如图:
问题就在于this.bar()的指向问题... 平时一般遇到this一般都会在本类里(这里就是T类)去找是否有将之实现的方法,若有,就是它了。
但是这次不同,事实上,正是this,使得当前方法指向其具体的对象,当这个对象实现了这个方法(这里的B类里将bar()方法覆盖了),自然this.bar()就会指向子类实现的这个bar()方法。
本质上,输出B.bar是方法覆盖的问题,但自己犯错的原因是this的指向问题。
因此,当我们稍微改一下代码。
将B类的bar方法注释掉,让其不能覆盖其父类T的bar方法,结果this依旧是指向B类对象,但要调用bar方法时,发现B类没有bar方法的实现,因此“追溯”到B的父类中去寻找bar方法,此时找到了父类的bar方法并将其调用,输出自然也就是T.bar(如图)。
此时,再来看另一种改动:只是在父类T中删掉了this,运行结果如图:
可以看到,程序的输出结果依旧是B.bar。(这或多或少超出了我的预料)
也就是说,这时的程序,和含有this关键字时,是一样的......
这道题给我的印象还是很深刻的,毕竟自己看完题之后,竟然一点儿都不谦虚地直接喊出了一个错误答案...
以后一定会多多注意this和super这样的很容易“改变”程序流程的关键字...