关于子类调用父类private函数的疑惑。

zidane1983 2009-09-02 03:17:59
最近看thinking in java时遇到了一点问题,请教一下大家。
示例代码如下:

abstract class Father {
private void test() {
System.out.println("this is Father.test()");
}
abstract void show();
Father() {
System.out.println("this is Father.Father()");
show();
test();
}
}

public class Child extends Father {
int radius;
void show(){
System.out.println("this is Child.show(),radius = " + radius);
}
Child(int r){
radius = r;
show();
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
new Child(7);
}
}


运行结果如下:

this is Father.Father()
this is Child.show(),radius = 0
this is Father.test()
this is Child.show(),radius = 7


我的理解:
首先我建造了一个抽象的父类Father类,其中有一个私有的函数test(),一个抽象的函数show(),然后
在Father的构造函数中,我调用了这两个函数。之后我建造了子类Child类,继承了父类Father类,并实
现了Father类的抽象函数show(),在Child类的main函数中我创建了一个Child类的实例。


疑惑:
按照初始化的顺序,我的理解是:
(1)首先分配给Child对象的成员变量radius初始值0.
(2)之后调用Father的构造函数,由于多态的特性调用show()函数时,实际上调用的是Child重写的show()函数。

(3)按照show()函数的打印结果,test()函数也应该像show()函数一样执行,由Child对象来调用,但是由于test()函数是private的,Child应该调用不到test()函数。而且abstract类是不会生成对象的,我不明白为什么会产生这样的打印结果?按照这个打印结果,那说明执行了一个this.test()的操作,但是abstract类是不会产生对象的呀。
(4)还有就是按照我写的这个程序,会不会产生一个Father的对象?














...全文
1148 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
zidane1983 2009-09-02
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 zangxt 的回复:]
变通的理解一下,比如
比如
Child child = new Child(7);
Father father = child;
这里father和child内容相同,不过是表现的类型不同。
类比一下,你可以认为父类构造方法中使用的this类型是Father,但是这个this的值就是子类对象引用的this值。
可能说起来比较绕。

只产生了一个对象,这是毋庸置疑的。那些说什么父类对象,子类对象的,基本是受了C++的影响。但java和C++毕竟不同,java的对象中起码需要有标识垃圾回收、线程状态的信息,所以从这个概念上讲,new得到的就是一个对象。不可能再为从父类继承的部分专门去添加这些状态信息,做垃圾回收管理,因此也就没有父类“对象”一说了。
[/Quote]

明白了,非常感谢!
zidane1983 2009-09-02
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 java2000_net 的回复:]
因为父类的构造器被调用了。

OVER
[/Quote]

紫竹大哥,貌似没看清楚问题。
老紫竹 2009-09-02
  • 打赏
  • 举报
回复
因为父类的构造器被调用了。

OVER
ZangXT 2009-09-02
  • 打赏
  • 举报
回复
变通的理解一下,比如
比如
Child child = new Child(7);
Father father = child;
这里father和child内容相同,不过是表现的类型不同。
类比一下,你可以认为父类构造方法中使用的this类型是Father,但是这个this的值就是子类对象引用的this值。
可能说起来比较绕。

只产生了一个对象,这是毋庸置疑的。那些说什么父类对象,子类对象的,基本是受了C++的影响。但java和C++毕竟不同,java的对象中起码需要有标识垃圾回收、线程状态的信息,所以从这个概念上讲,new得到的就是一个对象。不可能再为从父类继承的部分专门去添加这些状态信息,做垃圾回收管理,因此也就没有父类“对象”一说了。
zidane1983 2009-09-02
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 zangxt 的回复:]
test()方法是在父类的构造方法中调用的。
注意不要把构造函数和对象的创建联系起来。
创建对象在调用构造方法之前完成。
比如new Child(7);
的实际操作过程是:
1.根据Child的类型信息分配空间,创建对象,将所有的成员变量初始化为0.注意这里分配空间包括了父类定义的field占用的空间。
2.调用构造方法。构造方法的真正执行顺序是从顶层父类的构造方法开始,直到当前类的构造方法执行完毕。
[/Quote]

首先很感谢ZangXT大侠的回复,一直很关注你,知道你对JVM很有研究。
对于您的回复我还是有几个问题想问一下:
我现在已经清楚,构造函数与创建对象并不是一回事了。
(1)那这个父类的构造函数中是如何调用test()函数的呢。一般来讲按照我的写法,都是使用this.test()来调用的,那就等于说创建了一个对象,但是这个抽象类肯定是不会产生对象的啊。
(2)我可不可以理解按照我写的示例代码,实际上只产生了一个对象,就是Child对象,在调用父类的构造函数的时候也是这个对象在调用?
zidane1983 2009-09-02
  • 打赏
  • 举报
回复
哎,上网搜到了csdn spiniper的回复帖子。粘在这做个备份。
1、一般在java代码中,如果没有提供构造函数,把java编译成class文件时,jdk编译器会自动加上一个无参的构造函数,但是当jdk检测到 java代码中提供了构造函数代码,则不会添加构造函数了。检测方式就是在父类中你只提供一个有参的构造函数,子类继承必须显示调用构造函数,否则无法通过编译。
2、继承的概念只是针对类而不针对对象,当你new一个对象的时候不会生成所谓的父类实例,new只生成一个实例,而这个就是当前类的实例。在java代码中生成实例后会调用构造方法(构造方法是子类的),然后构造方法的第一句执行语句是调用父类构造方法,最后顺便说一句,构造方法本身是一个返回void 的方法名为 <init>的普通方法,生成实例在java代码中的表现形式是new关键字(在class指令中有一个固定指令代表生成实力以及为它分配内存空间)。
3、对于属性以及方法依赖的关系,继承其实是继承了父类中的所有,无论是private还是protected,只是子类无权限调用而已,利用反射可以调用private属性以及方法,由此可知道private其实是被继承了。但是为什么说不是子类对象调用父类对象的属性或者方法,理由很简单,我们可以做这样一个比对,就是内部类对象调用外部类对象与子类对象调用父类属性与方法的区别。
内部类对象在调用外部类对象的时候用会用"类名.this.方法或属性",这样就是一个对象调用另一个对象的方式,如果你查看编译后的class文件(利用反射获得所有属性名),你就会发现内部类的对象中有一个指向外部类的引用,内部类的无参构造函数其实是假的,编译器会自动提供一个隐含的外部类对象的参数(有参构造函数也会添加)。但是在继承关系中不存在这种子类指向父类引用,构造函数也不存在父类对象的参数。由此可见其实不存在子类对象调用父类对象的情况。因为一个对象调用另外一个对象是一定需要引用的,让对象知道另外一个对象的地址。
yanliang_xt 2009-09-02
  • 打赏
  • 举报
回复
抽象类不能被显示的实例化(也就是通过new),但是它可以自身进行实例化。
ZangXT 2009-09-02
  • 打赏
  • 举报
回复
test()方法是在父类的构造方法中调用的。
注意不要把构造函数和对象的创建联系起来。
创建对象在调用构造方法之前完成。
比如new Child(7);
的实际操作过程是:
1.根据Child的类型信息分配空间,创建对象,将所有的成员变量初始化为0.注意这里分配空间包括了父类定义的field占用的空间。
2.调用构造方法。构造方法的真正执行顺序是从顶层父类的构造方法开始,直到当前类的构造方法执行完毕。

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧