A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 夏天 初级黑马   /  2012-9-5 22:02  /  1481 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 夏诗瑶 于 2012-9-8 00:48 编辑

现在已知子类继承父类,子父类中都有 静态代码块,构造代码块,带参构造函数。
创建一个子类对象 Zi z=new Zi("lisi",20);
这句话,在内存中 是  如下实现的
// 1、因为new用到了Zi.class,并且子类继承了父类。所以会先找到Fu.class,再找到Zi.class文件并加载到内存中
// 2、执行 父类静态代码块
// 3、执行子类静态代码块
// 4、在堆内存中开辟空间,分配内存地址
// 5、在堆内存中建立对象的特有属性,并进行默认初始化
// 6、对属性显式初始化
// 7、子类构造代码块
// 8、子类构造函数
// 9、将内存地址付给栈内存中的z变量

现在问题是:
//a父类构造代码块
//b父类构造函数
ab 应该分别放在哪一步之前,哪一步之后?

评分

参与人数 1技术分 +1 收起 理由
唐志兵 + 1 赞一个!

查看全部评分

7 个回复

倒序浏览
// 1、因为new用到了Zi.class,并且子类继承了父类。所以会先找到Fu.class,再找到Zi.class文件并加载到内存中
// 2、执行 父类静态代码块
// 3、执行子类静态代码块
//a父类构造代码块
//b父类构造函数
// 4、在堆内存中开辟空间,分配内存地址
// 5、在堆内存中建立对象的特有属性,并进行默认初始化
// 6、对属性显式初始化
// 7、子类构造代码块
// 8、子类构造函数
// 9、将内存地址付给栈内存中的z变量
回复 使用道具 举报
本帖最后由 黑马--张帅 于 2012-9-5 22:41 编辑

a 父类构造代码块,b父类构造函数  对于这两步:因为你在子父类中都定义构造代码块和带参的构造函数,而现在你定义了一个子类对象,而在进行子类对象初始化时,子类都会调用父类的构造函数super()这句话一般是隐式的。而现在你的程序中没有定义无参构造函数,所以子类对象进行初始化时要显式定义父类构造函数super(s)。综上所述:在子类对象初始化时,都是父类构造函数先执行。然而构造代码块是对构造函数进行初始化的,所以a必定在b之前
// 1、因为new用到了Zi.class,并且子类继承了父类。所以会先找到Fu.class,再找到Zi.class文件并加载到内存中
// 2、执行 父类静态代码块
// 3、执行子类静态代码块
// 4、在堆内存中开辟空间,分配内存地址
// 5、在堆内存中建立对象的特有属性,并进行默认初始化
// 6、对属性显式初始化
//a父类构造代码块
//b父类构造函数
// 7、子类构造代码块
// 8、子类构造函数
// 9、将内存地址付给栈内存中的z变量
回复 使用道具 举报
本帖最后由 田旭阳 于 2012-9-5 22:39 编辑

1.class Parent{     
2.    static String name = "hello";     
3.    static {     
4.        System.out.println("parent static block");     
5.    }   
6.    {   
7.        System.out.println("parent block");   
8.    }   
9.    public Parent(){     
10.        System.out.println("parent constructor");     
11.    }     
12.}     
13.     
14.class Child extends Parent{     
15.    static String childName = "hello";     
16.    static {     
17.        System.out.println("child static block");     
18.    }   
19.    {   
20.        System.out.println("child block");   
21.    }     
22.    public Child(){     
23.        System.out.println("child constructor");     
24.    }     
25.}     
26.     
27.public class StaticIniBlockOrderTest {     
28.     
29.    public static void main(String[] args) {     
30.        new Child();//语句(*)     
31.    }     
32.}   
当执行完语句(*)时,打印结果是这样一个顺序:parent static block,child static block,parent  block,parent constructor,child  block,child constructor。
分析:当执行new Child()时,它首先去看父类里面有没有静态代码块,如果有,它先去执行父类里面静态代码块里面的内容,当父类的静态代码块里面的内容执行完毕之后,接着去执行子类(自己这个类)里面的静态代码块,当子类的静态代码块执行完毕之后,它接着又去看父类有没有非静态代码块,如果有就执行父类的非静态代码块,父类的非静态代码块执行完毕,接着执行父类的构造方法;父类的构造方法执行完毕之后,它接着去看子类有没有非静态代码块,如果有就执行子类的非静态代码块。子类的非静态代码块执行完毕再去执行子类的构造方法,这个就是一个对象的初始化顺序。

总结:对象的初始化顺序:首先执行父类静态的内容,父类静态的内容执行完毕后,接着去执行子类的静态的内容,当子类的静态内容执行完毕之后,再去看父类有没有非静态代码块,如果有就执行父类的非静态代码块,父类的非静态代码块执行完毕,接着执行父类的构造方法;父类的构造方法执行完毕之后,它接着去看子类有没有非静态代码块,如果有就执行子类的非静态代码块。子类的非静态代码块执行完毕再去执行子类的构造方法。总之一句话,静态代码块内容先执行,接着执行父类非静态代码块和构造方法,然后执行子类非静态代码块和构造方法。
父类Static->子类static->父类缺省{}->父类构造函数->子类缺省{}->子类构造函数

(静态变量、静态初始化块)>(变量、初始化块)>构造器
注意:子类的构造方法,不管这个构造方法带不带参数,默认的它都会先去寻找父类的不带参数的构造方法。如果父类没有不带参数的构造方法,那么子类必须用supper关键子来调用父类带参数的构造方法,否则编译不能通过。
// 1、因为new用到了Zi.class,并且子类继承了父类。所以会先找到Fu.class,再找到Zi.class文件并加载到内存中
// 2、执行 父类静态代码块
// 3、执行子类静态代码块
//a父类构造代码块
//b父类构造函数
// 4、在堆内存中开辟空间,分配内存地址
// 5、在堆内存中建立对象的特有属性,并进行默认初始化
// 6、对属性显式初始化
// 7、子类构造代码块
// 8、子类构造函数
// 9、将内存地址付给栈内存中的z变量

评分

参与人数 1技术分 +1 收起 理由
唐志兵 + 1

查看全部评分

回复 使用道具 举报
黑马--张帅 发表于 2012-9-5 22:12
a 父类构造代码块,b父类构造函数  对于这两步:因为你在子父类中都定义构造代码块和带参的构造函数,而现 ...

ab要插入上面的 顺序中。。。
回复 使用道具 举报
本帖最后由 郭阳 于 2012-9-5 22:45 编辑

顺序应该为
// 1、因为new用到了Zi.class,并且子类继承了父类。所以会先找到Fu.class,再找到Zi.class文件并加载到内存中
// 2、执行 父类静态代码块
// 3、执行子类静态代码块
// 4、在堆内存中开辟空间,分配内存地址
// 5、在堆内存中建立对象的特有属性,并进行默认初始化
// 6、对属性显式初始化
//a父类构造代码块
// 7、子类构造代码块
// 8、子类构造函数
//b父类构造函数
// 9、将内存地址付给栈内存中的z变量


构造代码块是对整个对象进行初始化,构造函数是对对象特定成员进行初始化,所以先是构造代码块,后是构造函数
构造函数,第一行都是super();或者this();**而this();最终也会被引向父类,所以父类的构造函数会先于子类的进行。
至于访问父类哪一个构造函数那就是你自己定义的了。
而构造代码块自然也是要先运行父类的。
所以顺序如上
回复 使用道具 举报
问题已解决,答案应该是  4,a,b,5
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马