黑马程序员技术交流社区

标题: 牛逼的大神们,有本事请来看看这段代码 [打印本页]

作者: 한숨짓다    时间: 2014-5-9 00:08
标题: 牛逼的大神们,有本事请来看看这段代码
本帖最后由 한숨짓다 于 2014-5-19 21:59 编辑

请看代码:

                                                                                                        
                                                                                                        
注解:这里的2种情况,首先我按照我知道的调用一个构造方法,是先执行成员因为只有成员存在了才去执行它的构造方法,让构造方法对成员进行初始化处理。另外,还得高清楚的是子类继承一个父类,启动子类的
          的构造方法,必须的首先调用父类的构造方法。这一点毋庸置疑。但是按照这样思想走,那为什么在情景一中会首先执行的X(){System.out.print("X");}后执行Y y=new Y()呢?这是第一点疑惑!!紧接着,情景          二中为什么首先执行的却是X类中的X(){System.out.print("X");},为什么不是像情景一种一样首先执行Y y=new Y(),这是第二点疑惑?
为了解决这个问题,我用debug进行测试看了一下执行的过程。感觉也挺奇怪的。
大神门,你们有点思路了吗?

作者: 谢振宣    时间: 2014-5-9 00:44
本帖最后由 谢振宣 于 2014-5-9 00:48 编辑
  1. class X
  2. {
  3.         Y y = new Y();//1.父类的显式初始化:Y
  4.         X()
  5.         {
  6.                 System.out.print("X");//2.父类的构造函数初始化:X
  7.         }
  8. }
  9. class Y
  10. {
  11.         Y()
  12.         {
  13.                 System.out.print("Y");
  14.         }
  15. }
  16. public class Z extends X
  17. {
  18.         Y y = new Y();//3.子类的显式初始化:Y
  19.         Z()
  20.         {
  21.                 System.out.print("Z");//4.子类的构造函数初始化:Z
  22.         }
  23.         public static void main(String[] args)
  24.         {
  25.                 new Z();//当创建子类对象时,会先加载其父类。并且显式初始化,先于构造函数的初始化。
  26.         }
  27. }
  28. //结果为:YXYZ
  29. //当将父类中的Y y = new Y();注释之后,父类就没有了显式初始化,结果就变成了:XYZ
复制代码

作者: 한숨짓다    时间: 2014-5-9 01:31
谢振宣 发表于 2014-5-9 00:44

你好!按照你的先执行显示初始化在执行构造方法,在第一种情景中应该是YYXZ而是真实的YXYZ。在第二种情景中为什么又不突然先执行Z类中的显示初始化了。你没有很清楚的说明。但是你的在最后的匿名对象中的注解是正确的。
作者: 谢振宣    时间: 2014-5-9 01:47
한숨짓다 发表于 2014-5-9 01:31
你好!按照你的先执行显示初始化在执行构造方法,在第一种情景中应该是YYXZ而是真实的YXYZ。在第二种情景 ...

创建子类对象,要先加载父类的成员,自然是既包括父类的显式初始化,也包括父类的构造函数初始化。
不然的话,父类的成员未加载完,就加载子类的成员,违背了父类先于子类加载的原则。
作者: lvc    时间: 2014-5-9 03:38
楼上解释得非常好,补充点,构造函数是在对象一建立就会自动调用。执行顺序是X-Y-Y()-X()-Z-Y-Y()-Z()
输出就是yxyz
作者: 走在道上发着呆    时间: 2014-5-9 11:22
我认为其实可以这样理解:
当我们执行:
Z z=new Z();的时候执行最先执行的就是Z的构造函数:
Z(){
super();默认隐藏
Z中成员变量=0://默认隐藏
成员变量的显示赋值//
this.xx=xx//构造函数中我们自己写的那些赋值
}
这样理解会好一点。
作者: 酱油炒饭    时间: 2014-5-10 11:14
路过菜鸟一只 长长知识~
作者: 苍穹的雨    时间: 2014-5-10 11:41
用子类创建对象的时候流程是这样的:创建父类成员-->调用父类构造函数-->创建子类成员-->调用子类构造函数
于是就出现了楼主情形里的情况了。
作者: jsjchenlong    时间: 2014-5-10 18:51
来学习一下。
作者: 한숨짓다    时间: 2014-5-19 21:50
通过最近的学习,发现这道题涉及到了分层初始化问题。并不是从构造方法入手,默认调用父类的构造方法,super()仅仅是一种标记作用,它提示要先去走父类的初始化。回顾一下在内容中创建对象的过程:加载class文件,在栈中申请引用类型变量空间,默认初始化成员变量,再显示初始化成员变量,完成代码块初始化工作,再去执行构造方法,在为new对象申请开辟空间,对象创建完了就将对象的地址赋值给引用类型变量存放。Y y=new Y()看作是X、Z类中的成员变量。由于Z类继承了父类X类,所以需要先初始化父类。那就就要走刚才我说的那个过程。先执行X类中的成员变量 Y y=new Y()然后再执行X(){}走完了X类,就走Z类执行 Y y=new Y()
再执行Z(){ }整个过程就是这样的。并不是其他同学那样想的,往构造方法那里去想。




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