[原创][2013.12.03]java多态 this 理解汇总

 

原帖地址:http://justt0.iteye.com/admin/blogs/1983634/edit

 

package com.p1;

public class Father {
	void test(){
		this.go();//即go();
	}
	void go(){
		System.out.println("father go");
	}
}

package com.p1;

public class Son extends Father {

	@Override
	void test() {
		// TODO Auto-generated method stub
		//指定super.test();
		super.test();
		//指定super.go();
		super.go();
	}

	@Override
	void go() {
		// TODO Auto-generated method stub
		System.out.println("son go");
	}

	public static void main(String[] args) {
		Father f = new Son();
		f.test();
	}
}

 

提到多态,首先要清楚创建子类的时候都发生了什么.(变量初始化总是在构造方法之前,我们在这里忽略它)我们知道执行new Son();后,由于继承关系,所以会先初始化父类---即会先创建一个父类对象(基对象这个对象是真实存在的,它和直接创建基类对象的区别是,前者的对象是包装在导出类的内部,后者则是外部),然后才是初始化子类--即创建子类对象,最后的结果是导出类对象(Son对象)的内部包装了一个基类对象(Father对象).

    我们再说创建对象的方式,Father f = new Son();这是将一个Son对象付给了一个Father引用,事实上f就是一个Son对象,但是这个f只能访问基类对象子类对象都有的方法,然后执行f.test();方法,因为f指向的对象其实还是一个Son对象,所以调用的test方法就是son对象的test方法.

    然后我们再说关键字this和super,有了上面的分析,我们可以将this认为是指向导出类对象,super指向的则是积累对象,有了这个思路,理解多态就容易多了.基类有两个方法,test()和go(),test调用go,在子类中我们覆盖这两个方法,父类的go()方法打印的是"father go",而子类的go()方法打印的是"son go",好了,go方法就这样,再说调用go方法的test方法,我们假设两种情况:

       情况一:子类的test方法里面调用父类的test方法,即super.test();看到这个super了吧,它指的就是基类对象,好了,这样我们直接找到基类的test方法,它调用的是go();,这个go();我们也可以写成this.go();(这个都清楚吧,两种写法一个意思),好了,this出现了,这个this指的就是子类对象,那我们直接就找子类的go()方法,所以打印的是"son go",怎么样?容易吧?

       情况二:子类的test方法里面直接调用父类的go方法,即super.go();看到super了吧,它指的是基类对象,这样我们直接找到父类的go()方法,所以打印的是"father go",即使子类有覆盖go()方法,没用.

    说到这里,有朋友可能会想到,如果子类没有覆盖父类的go方法,子类只是覆盖基类的test方法呢?  这其实又是两种情况,理解方法也很简单:

       情况一:如果子类的test方法执行的是super.test(),由于父类的test方法调用的是go()(即this.go();),这个this代指子类对象,但是子类对象并没有自己的go()方法,怎么办? 其实我们可以把它看成是一层一层的,如果子类没有go方法,那么它就会向里面找,所以就会找到父类的go()方法,所以就会打印出"father go"的结果.

       情况二:如果子类的test方法执行的是super.go(),直接找到父对象的go方法,没说的,打印的是"father go".

    可能有人又会想到,如果子类什么都没覆盖,只是继承了父类呢? 这其实又是一种情况,f.test();调用子类的test()方法,由于子类没有明确覆盖test方法,所以,向里找,在基类找到了test方法,然后test方法里调用了this.go();方法,this代指Son对象,在Son对象里又没找到明确覆盖的go()方法,所以又向里找,所以找到了基类对象的go()方法,所以打印的是father go.

 

 [2013.12.03]更新

今天看到IBM官网上的一篇文章,http://www.ibm.com/developerworks/cn/java/j-lo-polymorph/,印证了我的理解,首先,this指的就是实际的对象,不管引用对象的引用是什么,对象的类型是不变的,比如,Father f = new Son();即使引用Son对象的是Father的引用,但如果你试一下将f打印出来,然后再将f向上转型为son,然后将转型后对象打印出来,你就会发现两者打出来的结果是一致的,就是com.p1.Son@142c63f,为什么呢? 看下源码就会发现,如果system.out.println();打印一个object的话,调用的是该object的toString方法,源码是这样的:

   public String toString() {

        return getClass().getName() + "@" + Integer.toHexString(hashCode());

    }

意思是类的名字+@+对象的hashcode的16进制字符串表现形式,hashcode大家都知道,是唯一的,再看上面的结果com.p1.Son@142c63f,首先,即使是Father引用指向的他,但他还是一个Son对象,再看hashcode部分,转型前后@后面的都一样,说明,对象还是那个对象,没有产生新对象.

    接着,我们回到主题,http://www.ibm.com/developerworks/cn/java/j-lo-polymorph/,这篇文章有一幅描绘方法表的图:

 大概意思是,girl和boy都继承自object,我们拿girl来说,首先,girl复写了object的toString()方法,然后,girl又多了两个方法,eat()和speak(),对于一个girl对象来说如果调用girl的eat()方法,哪个箭头(我们把他看做指针),就会直接指向girl的eat();如果调用的是toStirng();方法,但是object有同名方法,怎么办? 答案是,指针会直接指向girl里面的toString();方法,而忽略掉object里面toStirng方法,这其实就是多态的实现,很清晰的思路,再说如果调用没有被girl复写的object方法,指针会直接指向object的方法代码,也很简单.

 

至于变量的覆盖,可以参照这篇文章,http://developer.51cto.com/art/201204/327772.htm和这篇文章http://blog.csdn.net/tryandlearn/article/details/8742367

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值