黑马程序员技术交流社区

标题: 有关初始化顺序的问题 [打印本页]

作者: Θ动@咚Θ    时间: 2013-11-11 11:58
标题: 有关初始化顺序的问题
  1. public class Demo24
  2. {
  3.         public static void main(String[] args)
  4.         {
  5.           A a=new A();
  6.         }
  7. }
  8. class A extends B
  9. {
  10.         int i=5;
  11.         static int j=4;
  12.         A()
  13.         {
  14.            System.out.println(i);
  15.            System.out.println(j);
  16.         }
  17.         void m()
  18.         {
  19.           System.out.println(i);
  20.           System.out.println(j);
  21.         }
  22. }
  23. class B
  24. {
  25.         B()
  26.         {
  27.           m();
  28.         }
  29.         void m()
  30.         {
  31.          
  32.         }
  33. }
复制代码
这是刚才一童鞋发的问题,程序运行出来结果是0454,本人菜鸟,不明白第一个数字为什么是0,有大神解答说是初始化顺序的问题,说是在调用m方法后才初始化i 变量。。。本人不慎明白,求解答,大神不在。于是我重新开一贴,求在线的大神们给小弟解答一下这个i变量的初始化顺序问题,跪求!

作者: Gump    时间: 2013-11-11 20:52
别沉了啊,我正在想。。。
作者: 文涛    时间: 2013-11-11 22:51
你仔细看你的代码,可以看到A继承与B,也就是说构造A之前会构造B。
    毕老师讲过,其实在A的构造函数A()中,第一行有一个super();语句,只是我们看不见,在实例化对象的时候有一个初始化顺序,最先是初始化静态成员,然后构造父类,父类构造完成才初始化非静态的成员。
    于是,在这里,在初始化int i=5之前就先执行了super()构造父类,从而调用了父类B的构造函数B(),在B()中会调用m()方法,由于父类的m方法被子类重写,于是,调用了子类的m方法,从而开始打印i,这时i还没有初始化为5,只是默认的0,所以打印了0,但是,j是一个静态变量,静态成员变量是在类初始化时就初始化的,所以,j先与对象存在,于是j打印出了5,随后,继续执行两句打印语句,在父类初始化完成后,i也进行了初始化为5的操作,于是后面的语句就成了5和4.
    总之初始化的顺序就是,首先初始化你要创建的类的静态成员,然后初始化该类的父类对象,随后初始化非静态成员,然后执行该类的构造函数的其他语句。
作者: 起猿    时间: 2013-11-12 01:27
直接上代码,如果有错误的,希望看到的大神及时给予改正。共同进步

  1. <P> </P>
复制代码
  1. /**
  2. * 为了区分打印的是哪一步,我再输出语句后面分别加了一个不同的字符串。
  3. * 程序的运行顺序如下。
  4. */
  5. public class Test
  6. {
  7. public static void main(String[] args)
  8. {
  9. A a=new A();//第一步,先创建了A类的对象。创建对象后,加入内存中,需要通过A类的构造函数对这个对象进行初始化。
  10. }
  11. }


  12. class A extends B
  13. {

  14. int i=5;//第七部,变量i赋值。i=5
  15. static int j=4;//第五步,因为这里是static修饰的变量,随着类的初始化而初始化。而上面的是普通的变量。所以这里内存中只给了它默认值0。
  16. A()
  17. {

  18. super();//第二步,在构造函数中,第一行代码有一个默认的super()对父类的引用。那么这个子类A就通过这里引用到了B类的无参构造函数。
  19. //就是我们通常说的,创建对象时,程序先初始化父类构造函数。
  20. System.out.println(i+"aa");//第八步,这里接下来的输出,就一目了然了。所以为什么你那里输出0454.应该很清楚了吧。
  21. System.out.println(j+"bb");
  22. }
  23. void m() //第四部,回到A类时,就是B类中得该初始化的都初始化完毕了,接下来该初始化A类中要初始化的成员了。这里就转到A类的变量。
  24. {
  25. System.out.println(i+"cc");//第六步,接下来的输出这两句就很明白了。这个时候i=0 j=4。
  26. //这个时候才结束初始化动作,然后才到变量i的赋值。
  27. System.out.println(j+"dd");
  28. }
  29. }
  30. class B
  31. {
  32. B()
  33. {
  34. m();//第三步,这一步骤开始对B类进行初始化,调用这个方法。由于是A对象,所以这个时候是A对象来调用m方法。这在内存中体现的是多态的步骤。多态中,
  35. //子类对象调用方法,只能是自己的方法。所以,这里就返回到A类中的m方法中。B类中的方法,根本不会被执行。
  36. }
  37. void m()
  38. {
  39. System.out.println("aaaaa");//所以这里为了验证,而添加的代码根本不会被执行到。
  40. }
  41. }
复制代码

作者: Θ动@咚Θ    时间: 2013-11-12 09:37
文涛 发表于 2013-11-11 22:51
你仔细看你的代码,可以看到A继承与B,也就是说构造A之前会构造B。
    毕老师讲过,其实在A的构造函数A() ...

爱死你了!!!!!
作者: Θ动@咚Θ    时间: 2013-11-12 09:44
起猿 发表于 2013-11-12 01:27
直接上代码,如果有错误的,希望看到的大神及时给予改正。共同进步

哥们你说的很详细,只是有一点我和你有异议。我认为,static的j是在执行A a=new A()这一步时就被赋值加载了,因为这一步时A类被加载入内存中,A中的静态变量就也直接在方法区中创建赋值了。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2