多态(真的搞不明白!)
abstract class Hello{
abstract void print();
Hello(){
print();
}
}
class Hi extends Hello{
int i = 5;
void print(){
System.out.println("Hi.i="+i);
}
}
public class Test{
public static void main(String[] args){
Hi hi = new Hi();
hi.print();
}
}
//结果:Hi.i=0 Hi.i=5
Hello中是怎么调用Hi中的print()的?想不明白?
问题点数:20、回复次数:23Top
1 楼steedhorse(晨星)回复于 2005-04-04 17:36:57 得分 5
你要研究语言的底层实现么?
还有,你的程序根本没有从Hello类型上调用High。Top
2 楼zephyer(zephyr)回复于 2005-04-04 17:39:40 得分 3
搞不明白就记住结论好了:使用基类句柄调用方法,会调用实际引用的对象的方法
学习java也不必要把这些实现细节搞清楚
也没有几本java的书讲解了这些实现细节,包括Thinking in java
java注重的是思想
真要想搞明白多态的实现细节,看看thinking in C++之类C++书籍的相关章节,会讲解的很详细,也需要知道很多的基本知识
Top
3 楼leqixb(清然)回复于 2005-04-04 17:39:58 得分 0
anyone help me?
我在重看thinking in java,可是还有n个问题不明白!Top
4 楼milkbottle(奶瓶->好好学习,天天向上)回复于 2005-04-04 17:45:04 得分 1
因为 Hello 中的 print()已经被复写了,所以在这个过程中,可见的只有 Hi.print()
Hi.i=0 // 调用父类构造函数, 此时 Hi.i 还未被赋值, 只是被初始化为0
Hi.i=5 // 已经被赋值, 所以是5
Top
5 楼kingfish(工作很忙,很少来csdn...)回复于 2005-04-04 17:49:44 得分 5
先父类构造-再子类构造
i还没初始化,只是缺省值。Top
6 楼leqixb(清然)回复于 2005-04-04 17:56:55 得分 0
我是不明白在调用父类的构造函数时为什么会调用子类中的方法,难道真如milkbottle说的可见的只有 Hi.print()?忘继续指点!Top
7 楼ysbcg(Hummer)回复于 2005-04-04 18:04:08 得分 1
这个是动态绑定的作用,你在任何一个最终的对象中调用任何函数,他们的动态指向都是这个对象所对应的那个类所作的操作,这就是动态绑定。Top
8 楼menghuanlang(梦幻狼)回复于 2005-04-04 18:15:00 得分 0
我个人赞成
kingfish(八百里秦川@龙城异客)
的观点!Top
9 楼zephyer(zephyr)回复于 2005-04-04 18:18:09 得分 0
不是只有Hi.print()可见
而是编译器会根据具体的对象去决定调用哪个版本的方法
更具体的实现这里就不要讨论了,方法指针之类的概念java中都没有,仅仅学习java是无法进行详细的讨论的
Top
10 楼steedhorse(晨星)回复于 2005-04-04 18:32:17 得分 0
“我是不明白在调用父类的构造函数时为什么会调用子类中的方法。”
Java中任何方法的调用都是多态的,即使在构造函数中也如此。只要这个方法被重写,那么被调用的就永远是继承链中那个“lastest overider”。Top
11 楼steedhorse(晨星)回复于 2005-04-04 18:39:17 得分 0
Java程序的执行,首先是源文件编译成二进制的类文件,一旦编译成类文件,就可以说所有的为实现多态所需要的准备工作都已经做好了。
比如你上面的例子,生成了class文件之后,其实不管是基类也好,派生类也好,所有调用print的地方并不是已经绑定到了具体的print方法的地址,而只是标记了一个入口,表示“这个地方要执行一个叫做print的函数。”(当然,实际上未必使用字符串标记),当运行时运行到那一步的时候,虚拟机就会根据继承链,来查找能在Hi类的对象上(因为hi实际是Hi类的对象)找到的print的最后一份实现,找到后,就执行它。
其实还有一个很明显的问题,Hello类自己也没有print的实现啊。Top
12 楼steedhorse(晨星)回复于 2005-04-04 18:41:56 得分 0
总之只需要记住:构造函数里照样可以多态,在这一点上跟一般函数没什么区别。
至于“对象还没构造好,怎么就多态了?”,原因是对象的内存已经分配好了,多态的条件已经完全具备了,构造函数不是负责分配内存的,内存由JVM分配,构造函数只是在JVM分配给对象的内存上做一些初始化的动作,从而初始化那块内存里的一些内容而已。Top
13 楼kingfish(工作很忙,很少来csdn...)回复于 2005-04-04 18:49:19 得分 0
楼上说得不错
不过有1句
//"其实还有一个很明显的问题,Hello类自己也没有print的实现啊。"
即使Hello类实现了print,这个例子中也不会调用
Hi hi = new Hi();
=====
这个是什么类型,那就会调用该类的print
Top
14 楼steedhorse(晨星)回复于 2005-04-04 19:02:52 得分 0
“即使Hello类实现了print,这个例子中也不会调用”
同意,俺只是补充一下,让楼主别忽略了这一点,在楼主的例子中,基类根本没有print的实现的。
Top
15 楼kingfish(工作很忙,很少来csdn...)回复于 2005-04-04 19:08:42 得分 0
同意+理解,呵呵
楼主想明白了就可以揭贴了。如果对底层实现很感兴趣,可以看看inside JVM之类书或JVM spec.Top
16 楼steedhorse(晨星)回复于 2005-04-04 19:18:34 得分 0
同意。:PTop
17 楼lxt322625(霞涛)回复于 2005-04-04 20:31:09 得分 2
Abstract (抽象类)没有任何的功能 只是一个抽象的结构 所有的功能要求在子类中继承和实现 需要保证定义的方法必须被子类重载
抽象类不能创建一个实例化的对象 也不能声明一个抽象构造函数或抽象静态的方法 抽象类只能被继承而派生子类 所有继承抽象类而派生的子类必须实现父类的抽象方法Top
18 楼wangsheng1028(java菜)回复于 2005-04-04 23:23:04 得分 1
即使父类不是abstract也是一样的结果
那就是因为多态造成的。
他执行的是他的实际方法,子类的方法,但是在那时候i初始化还没被赋值。Top
19 楼bestdelphier(菜鸟升级中......)回复于 2005-04-05 00:32:42 得分 0
学习一下Top
20 楼slh002(呵呵)回复于 2005-04-05 00:47:00 得分 0
不太懂Top
21 楼ifmirror(镜子)回复于 2005-04-05 03:22:11 得分 1
若子类有覆盖父类的方法,那么指向子类对象的父类变量调用了该方法,被执行的会是子类的方法。Top
22 楼gtoliushan(k.m)回复于 2005-04-05 06:21:25 得分 1
abstract class A
{
abstract void print();
}
class B extends A
{
void print()
{
System.out.println("b");
}
public static void main(String args[])
{
A a=new B();
a.print();
}
}
看A类是一个抽象类。里面有一个抽象函数print,现在B类继承了A类。并且把A类的为被实现的print重写。也就是覆盖。现在看main()函数里面创建了一个A类的引用也就是a。他引用B类的无名对象。这时候a调用print函数。他输出的也就是B类的print。这就是多态。说白了就是a是基类的引用指向B类的对象。这时候a就可以调用B类的覆盖函数了。Top
23 楼leqixb(清然)回复于 2005-04-05 10:48:10 得分 0
谢谢各位,说很明白那是不可能的,还得在今后的实践中锻炼,结帖!Top




