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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 代文娟 中级黑马   /  2013-11-10 15:31  /  1043 人查看  /  9 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

为什么下列代码输出的结果是:0 4 5 4
  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. }
复制代码

评分

参与人数 1技术分 +1 收起 理由
黄炳期 + 1

查看全部评分

9 个回复

倒序浏览
12.        A()
13.        {
                super();     //调用父类的构造方法,默认调用无参,被省略
14.           System.out.println(i);
15.           System.out.println(j);
16.        }

new A(); 的运行顺序是:
1. 如果有静态代码块:
    static { 。。。 }
    则先运行静态代码块,如果没有,则跳过该步骤
2. 构造方法:
2-1. super(); 调用父类构造方法: B(){ m(); }
    因为子类重写(Override)了 m() 方法,所以B的构造方法会调用重写后的m()方法,
    这时候 i 和 j 都还没有被赋值(下一步才会对成员变量赋值),
    但 j 是静态变量,静态变量如果没有在静态代码块中被赋值,则会在第一次被调用的时候赋值,
    所以 这时候 i=0;j=4
2-2. 成员变量初始化:这时候 i=5
2-3. 运行 A 的构造方法代码:输出 i=5,j=4

所以是 0,4,5,4

评分

参与人数 1技术分 +1 收起 理由
黄炳期 + 1 不给你加分都不好意思了哈哈

查看全部评分

回复 使用道具 举报
楼上的:
12.        A()
13.        {
                super();     //调用父类的构造方法,默认调用无参,被省略
14.           System.out.println(i);
15.           System.out.println(j);
16.        }

super父类构造函数,在子类还没有构造时就已经表现处理多态的特性?可以操作子类的m()?
13.        {
                super();     //调用父类的构造方法,默认调用无参,被省略
回复 使用道具 举报
零下五度的水 发表于 2013-11-10 15:51
12.        A()
13.        {
                super();     //调用父类的构造方法,默认调用无参,被省略

向大神求教,你写的前几步我都能理解,但是到成员变量赋值的时间这一点我不是很理解。B的构造方法调用被重写的m方法时候,为什么这个时候i和j都还没有被赋值呢?这个时候a对象已经被实例化了,为什么这个时候变量 i 还没有被赋值?
回复 使用道具 举报
创建一个对象也是通过编程实现的,既然是编程就一定有一个顺序问题,要明确先干嘛然后干嘛接着干嘛,
1. 通过自己的构造方法调用父类构造方法(如果没有明确指明的话,就调用父类的无参构造方法)
【super父类构造函数,在子类还没有构造时就已经表现处理多态的特性?可以操作子类的m()?】
这个我也不清楚,不过既然运行的结果是这个,自然得顺着这个结果来分析
调试的结果是,父类构造中的m() 并没有进入父类的m()方法中(我在其中添加了语句也一样),
而是直接进入了子类的m() 方法,所以我猜想,复写的方法应该是创建父类数据的时候创建的
【为什么这个时候i和j都还没有被赋值呢】
因为这个时候还在创建父类的数据,创建完父类的数据才会创建子类的数据
或者是先创建子类数据(先在内存里把地方占上),然后创建父类数据,
然后父类数据赋值,然后子类数据赋值,
这个是虚拟机处理流程的问题,我看过一点,不过早就忘的差不多了,
反正现象是摆在那了,你自己找个感觉能说得通的分析就是了,
什么时候等你学到虚拟机了,自然就能想明白了
回复 使用道具 举报
零下五度的水 发表于 2013-11-11 12:00
创建一个对象也是通过编程实现的,既然是编程就一定有一个顺序问题,要明确先干嘛然后干嘛接着干嘛,
1. 通 ...

我大概明白了,看看是不是这么个回事。main函数中调用A的构造函数,这时内存中仅仅加载了A类,没有创建A的数据。A继承了B,所以在加载A之前还要加载B,也不创建B的数据(相当于A类和B类仅仅在内存中占个地方)。
然后执行A构造方法,第一步先执行super():执行B()方法,调用被重写的m()方法。这时是向A类中取数据,但是内存中只有静态的j,还没有给i赋值,所以能取到j,取不到i。至此,super执行完毕,执行流从B类退出。
第二步:super()结束,执行流回到A类构造方法,开始打印i和j,因为执行流的回归,表示B的数据都创建完毕,这时需要开始创建A的数据,此时就需要给i赋值了。
回复 使用道具 举报
Θ动@咚Θ 发表于 2013-11-11 12:33
我大概明白了,看看是不是这么个回事。main函数中调用A的构造函数,这时内存中仅仅加载了A类,没有创建A ...

棒,我就是这么想的,对不对不保证,不过目测是不会差太多,毕竟结果摆在那
回复 使用道具 举报
本帖最后由 零下五度的水 于 2013-11-11 12:43 编辑

-                                         -
回复 使用道具 举报
帖子已分类
回复 使用道具 举报
多谢大家了,大概明白了
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马