原帖地址: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
相关推荐
java多态、继承练习题,包含题目与答案,............................................................................................................
JAVA多态的理解.pdf
.archivetemp04 - 继承和多态 作业.doc
java多态的理解共3页.pdf.zip
编程语言JAVA多态的理解.pdf
java的多态,是一个很重要的环节.但是要知道什么是多态!
【Java面试题】谈谈对Java多态的理解
代码演示对java中多态的理解 从代码演示中更好的理解多态的作用
计算机后端-PHP视频教程. php之面向对象29 多态(选学).wmv
java 个人对于多态理解和一些笔记。
Java多态的讲解
【IT十八掌徐培成】Java基础第06天-03.多态-类多态-接口多态-同名属性问题.zip
C++开发基于多态的公司职工管理系统(课设源码).zipC++开发基于多态的公司职工管理系统(课设源码).zipC++开发基于多态的公司职工管理系统(课设源码).zipC++开发基于多态的公司职工管理系统(课设源码).zipC++开发基于...
Python工具箱.zip - 办公自动化、多态文件搜索、高级加密。Python工具箱.zip - 办公自动化、多态文件搜索、高级加密。Python工具箱.zip - 办公自动化、多态文件搜索、高级加密。Python工具箱.zip - 办公自动化、多态...
本文带您通过几个类的示例和讲解来理解Java多态性,Java多态性的概念也可以被说成“一个接口,多个方法
JAVA多态图文详解ppt,详细通过各种举例介绍JAVA多态的ppt
这边文章的编程代码:https://blog.csdn.net/qq_41086359/article/details/103650238 Java多态,面向对象编程题
Java 多态中的类型转换