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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 林康春 黑马帝   /  2012-7-8 23:38  /  2752 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 林康春 于 2012-7-9 23:35 编辑

class Root
{
static {
  System.out.println("1:Root静态构造代码块") ;
}   
{
  System.out.println("2:Root普通构造代码块") ;
}
public Root() {
  System.out.println("3:Root构造函数") ;
}
}
class Mid extends Root
{
static {
  System.out.println("4:Mid静态构造代码块") ;
}
{
  System.out.println("5:Mid普通构造代码块") ;
}
public Mid() {
  System.out.println("6:Mid无参构造函数") ;
}
public Mid(String msg) {
  this ();
  System.out.println("7:Mid有参构造函数"+msg) ;
}
}
class Leaf extends Mid
{
static {
  System.out.println("8:Leaf静态构造代码块") ;
}
{
  System.out.println("9:Leaf普通构造代码块") ;
}
public Leaf() {
  super("疯狂java讲义");
  System.out.println("10:Leaf有参构造函数") ;
}
}
public class Demo6 {
public static void main(String[] args) {
  new Leaf() ;
}
}

请解释解释,我不是很清楚了,今天晚上弄了半天也没弄清楚

7 个回复

倒序浏览
要弄明白程序的执行顺序首先要明白 继承继承静态代码块构造代码块构造函数 的执行顺序,他们的顺序是:
父类静态代码块>>子类静态代码块>>父类构造代码块>>父类构造函数>> 子类构造代码块>>子类构造函数。
执行步骤(个人见解)
class Root    //第5步:找到Root,开始执行
{
static {  //第6步:由于有静态代码块,先执行静态代码块,进行初始化,打印1:Root静态构造代码块
  System.out.println("1:Root静态构造代码块") ;
}   
{   //第9步:执行父类的构造代码块,打印2:Root普通构造代码块
  System.out.println("2:Root普通构造代码块") ;
}
public Root() { //第10步:执行父类构造函数,打印3:Root构造函数
  System.out.println("3:Root构造函数") ;
}
}
class Mid extends Root    //第4步:找到Mid类,他又继承了Root,再去找Root类
{
static {     //第7步:Root初始化完成后寻找子类,也有静态代码块,先执行,并打印4:Mid静态构造代码块
  System.out.println("4:Mid静态构造代码块") ;
}
{   //第11步:执行性次构造代码块 打印5:Mid普通构造代码块
  System.out.println("5:Mid普通构造代码块");
}
public Mid() { //第12步:执行此构造函数,打印6:Mid无参构造函数
  System.out.println("6:Mid无参构造函数") ;
}
public Mid(String msg) {   //第13步:执行此构造函数打印7:Mid有参构造函数"+msg,msg由Leaf()调用super传入疯狂java讲义,所以打印Mid有参构造函数疯狂java讲义
  this ();
  System.out.println("7:Mid有参构造函数"+msg) ;
}
}
class Leaf extends Mid   
{
static {    //第8部:理由同第六步,打印8eaf静态构造代码块。静态代码块都完成了,再找父类的构造代码块
  System.out.println("8eaf静态构造代码块") ;
}
{   //第14部最后执行子类的构造代码块,打印9eaf普通构造代码块
  System.out.println("9eaf普通构造代码块") ;
}
public Leaf() {   //第2步,要new对象,找到Leaf的构造函数
  super("疯狂java讲义");  //第3步,调用父类,并且有参数 疯狂java讲义
  System.out.println("10eaf有参构造函数") ;  //第15步,打印10eaf有参构造函数
}
}
public class demo {
public static void main(String[] args) {
  new Leaf() ;        //第1步:找到main方法开始执行这一句
}
}
回复 使用道具 举报
哥们你这代码太让人崩溃了……不过为了技术分,咱拼了!
关于对象初始化的问题,我也找了很多资料,写了很多测试代码,我就来说说吧
对象的初始化,有以下几项原则:
1.静态代码块,静态变量的显式初始化,会在类加载完成后进行
2.只是建立对象引用,类是不会加载的,只有要new 对象时,或者需要访问静态成员时,类才会加载

3.这条很重要,new出子类之前,会先去加载父类,也就是说先加载父类,再加载子类
4.构造代码块和成员变量的显式初始化会优先于构造函数执行,并且,构造代码块会在每一个构造函数之前执行
5.子类构造函数一定会调用父类的构造函数,如果程序员不调用,那么系统就默认调用父类的无参构造函数,当然程序员自己也可以手动调用

6.这条非常重要,构造函数并不是用来new对象的,而是对new出来的对象进行初始化的!!!

好,明确了这几点,我们再看代码,从main函数开始:
1.new Leaf();   使用Leaf()来创建Leaf对象,在这之前先加载父类 Mid,并使用Mid的构造代码块和 Mid(String msg) 对自己进行初始化,,
2.而Mid(String msg)又调用了Mid(),同理,在这之前又去加载Mid 的父类 Root了,并使用Root的构造代码块和 Root() 对自己进行初始化
3.此时Root加载完毕,接着执行他的静态代码区(这里我们不考虑Object,要不就太麻烦了)
4.Root 搞完了就该 Mid了,同样的,先执行静态代码区
5.Mid 加载完了 就该 Leaf了,同样执行 静态代码块,
6.所有的类都类加载完毕,静态代码区也都执行完了,那接下来就该是对象的初始化了
7.初始化的顺序就是:先使用父类的构造代码块和父类的构造函数初始化,在调用自己的构造代码块和构造函数
8.接下来就不多说了,先执行构造代码块,再执行构造函数,按照父子类构造函数的调用顺序逆向进行
按照上面所说,打印顺序为:
1:Root静态构造代码块
4:Mid静态构造代码块
8Leaf静态构造代码块
2:Root普通构造代码块
3:Root构造函数
5:Mid普通构造代码块
6:Mid无参构造函数
7:Mid有参构造函数疯狂java讲义
9Leaf普通构造代码块
10Leaf有参构造函数

以上一部分是我自己的理解,一部分是看书,上网找来的,这个初始化问题实在是太复杂了,希望对你有帮助


点评

这哥们儿说的真不错!  发表于 2012-7-9 12:20
回复 使用道具 举报
需要明白父类和子类的静态代码块、构造代码块和构造函数的执行顺序:
首先执行父类静态的内容,父类静态的内容执行完毕后,接着去执行子类的静态的内容,当子类的再去看父类有没有非静态代码块,如果有就执行父类的非静态代码块,父类的非静态代码块执行完毕,接着执行父类的构造方法;父类的构造方法执行完毕之后,它接着去看子类有没有非静态代码块,如果有就执行子类的非静态代码块。子类的非静态代码块执行完毕再去执行子类的构造方法。
总之一句话,父类和子类的静态代码块内容先执行,接着执行父类非静态代码块(构造代码块)和构造方法,然后执行子类非静态代码块(构造代码块)和构造方法。
简单记住这样的顺序:父类Static->子类static->父类构造代码块->父类构造函数->子类构造代码块->子类构造函数
这里我想提醒需要注意的是:子类的构造方法,不管这个构造方法带不带参数,默认的它都会先去寻找父类的不带参数的构造方法。如果父类没有不带参数的构造方法,那么子类必须用super关键子来调用父类带参数的构造方法,否则编译不能通过;如果是多级继承关系的话,最高层的父类首先执行,然后依次递减。
因此你的程序的执行顺序是这样:从main函数开始,执行new Leaf(),由于这里是多级继承,要从最高层次的父类Root类开始,接下第一步执行Root的静态代码块,第二步执行Mid的静态代码块,第三步执行Leaf的静态代码块,第四步执行Root的构造代码块,第五步执行Root的构造函数,第六步执行Mid的构造代码块,第七步执行Mid的构造函数,这里由于Leaf的构造函数调用了Mid的有参数的构造函数,所以这里仍遵循父类构造函数优先于子类的构造代码块,第八步执行Leaf的构造代码块,第九步执行Leaf的构造函数,这样就结束了。
最后的输出结果应该是
1:Root静态构造代码块
4:Mid静态构造代码块
8:Leaf静态构造代码块
2:Root普通构造代码块
3:Root构造函数
5:Mid普通构造代码块
6:Mid无参构造函数
7:Mid有参构造函数疯狂java讲义
9:Leaf普通构造代码块
10:Leaf有参构造函数

评分

参与人数 1技术分 +1 收起 理由
韦念欣 + 1 那3个红色的地方总结的很不错!.

查看全部评分

回复 使用道具 举报
高原 发表于 2012-7-9 01:14
哥们你这代码太让人崩溃了……不过为了技术分,咱拼了!
关于对象初始化的问题,我也找了很多资料,写了很 ...

这第6条说:构造函数不是用来new对象的?
那我这样:Person p = new Person();这样的声明就能创建对象?
然后再调用构造函数来进行对象的初始化操作?
回复 使用道具 举报
黑马-王言龙 发表于 2012-7-9 07:06
这第6条说:构造函数不是用来new对象的?
那我这样:Person p = new Person();这样的声明就能创建对象?
...

是的,new 这个关键字就是在内存中开辟对象的空间,此时对象就已经存在,只是此对象的成员变量都还是空值,然后再通过构造函数对这个对象进行初始化
回复 使用道具 举报
非常感谢各位的解答,明白了
回复 使用道具 举报
万宝东 发表于 2012-7-9 01:06
要弄明白程序的执行顺序首先要明白 继承继承静态代码块构造代码块构造函数 的执行顺序,他们的顺序是:
父 ...

神贴 神人  佩服 ;厉害 我当时震惊了 我看了这代码 都迷糊哈哈
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马