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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 万宝东 中级黑马   /  2012-7-4 20:21  /  1852 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 万宝东 于 2012-7-5 07:59 编辑

class B{
    private int radius = 10;
    public void draw(){
    System.out.println("B.draw(),radius = "+radius);
}
    public B(){
    System.out.println("B constructor");
    draw();
    }
}
public class A extends B{
    private int radius = 1;
    public void draw(){
    System.out.println("A.draw(),radius = "+radius);
    }
    public A(int radius){
    this.radius = radius;
    System.out.println("A constructor");
    }
   public static void main(String[] args){
   A a = new A(5);
   }
}

运行结果是
B constructor
A.draw(), radius = 0
A constructor

对于这个程序的运行顺序我觉得 :运行A a = new A(5);时,程序开始执行
public A(int radius){
    this.radius = radius;
    System.out.println("A constructor");
    }
这个方法体,此时会调用父类的构造方法
打印B constructor,然后运行父类的draw()方法,由于子类重写了draw()方法,会执行System.out.println("A.draw(),radius = "+radius);这一句,但是打印结果却是A.draw(), radius = 0。我实在是想不明白。
为什么radius的值不是 1 或者5 或者10 呢?

评分

参与人数 1技术分 +1 收起 理由
蒋映辉 + 1

查看全部评分

7 个回复

倒序浏览
下面是总结了一些关于子父类构造方法执行的顺序:
1,设置成员的值为默认的初始值(0,false,null)。
2,调用对象的构造方法(但是还没有执行构造方法体)。
3,调用父类的构造方法。
4,使用初始化程序和初始块初始化成员。
5,执行构造方法体。
回复 使用道具 举报
哥们帮你读一下这个程序哈,
进入主函数
A a 这个时候class A加载到内存的方法去中,并给这个地方命名为a ,由于A继承了B所以A初始化之前要先初始化B,然后调用了B的无参构造,接着执行了这一句 System.out.println("B constructor");然后运行到了 draw();这,本来吧应该用父类的,但是子类已经把其它复写了,既然子类的已经有了,又是建立的子类的对象,所以就调用的是子类的 draw();方法,也就是输出这句  System.out.println("A.draw(),radius = "+radius);然后这里呢radiues变量还有初始化,也就是还是默认初始化的值,所以你打印出来了就是A.draw(), radius = 0这个了
然后这有一篇老师总结的你看了这个估计会更明白哈
对象的建立以及初始化过程,说出Person p = new Person();到底在内存中做了什么事情?
   (1)将Person.class文件加载进内存。
(2)如果p定义函数中,那么在栈内存空间中开辟一个变量空间p。
(3)在堆内存中给对象分配空间。
(4)给对象中的属性进行默认初始化。
(5)给对象中的属性进行显示初始化。
(6)调用构造代码块对对象进行初始化。(执行类中的构造代码块,没有就不执行)
(7)调用对应的构造函数进行对象初始化。对象初始化完毕。
(8)将对象的内存地址赋值给p变量,让p变量指向该对象。


评分

参与人数 1技术分 +1 收起 理由
蒋映辉 + 1

查看全部评分

回复 使用道具 举报
本帖最后由 邵阳 于 2012-7-4 22:21 编辑
yufeiant 发表于 2012-7-4 21:45
哥们帮你读一下这个程序哈,
进入主函数
A a 这个时候class A加载到内存的方法去中,并给这个地方命名为a  ...


虽然是先初始化,但是radious有值啊,怎么不显示初始化啊
回复 使用道具 举报
public A(int radius){
    //super(); new A(5)一实例化,先执行此句,执行完才执行下面的语句,即是说参数5还没传给radius
    this.radius = radius;             //把5赋值给radius
    System.out.println("A constructor");
    }
不妨在main方法里加一句a.draw();打印的是A.draw(),radius = 5,new A(5)已经执行完,即子类构造函数初始化完毕(在此之前父类的构造函数必然先初始化完毕)并把5传给了radius

private int radius = 1;//"=1" 就是误导人的,赋不赋值都无所谓的,已经被private修饰了,外部不能直接拿到radius,需通过构造方法public A(int radius)给radius传int类型的参数值获取。
回复 使用道具 举报
我也觉得很奇怪,父类构造函数中调用draw方法,这本来就是一件奇怪的事,更奇怪的是,它又跑去调用子类的draw方法去了,这里面的参数赋值
会经历怎样的情况呢?我不清楚。但至少我不会去写这么令我迷惑的代码。建议不要在构造方法里面调用成员函数吧!!!!这样会出问题的。改成
下面这种形式,一切都正常了!!!
class B {
        private int radius = 10;

        public void draw() {
                System.out.println("B.draw(),radius = " + radius);
        }

        public B() {
                System.out.println("B constructor");
        }
}

public class A extends B {
        private int radius = 1;

        public void draw() {
                System.out.println("A.draw(),radius = " + radius);
        }

        public A(int radius) {
                this.radius = radius;
                System.out.println("A constructor");
        }

        public static void main(String[] args) {
                A a = new A(5);
                a.draw();
        }
}
执行结果如下:
B constructor
A constructor
A.draw(),radius = 5
回复 使用道具 举报
通过各位的回答,我总结一下:
1、子类B继承父类A,在实例化子类B的过程中,先调用父类A无参的构造方法,然后再调用子类B具体的(根据参数个数和类型)构造方法。
2、如果子类B继承父类A的方法,则将调用子类B重写父类A的方法。
3、类实例化的过程中,调用成员方法时,如果成员方法访问类的相关属性就会得到默认初始化值(类静态成员除外)。
回复 使用道具 举报
class B{
    private int radius = 10;
    public void draw(){
    System.out.println("B.draw(),radius = "+radius);
}
    public B(){
    System.out.println("B constructor");
    draw();
    }
}
public class A extends B{
    private int radius = 1;
    public void draw(){
    System.out.println("A.draw(),radius = "+radius);
    }
    public A(int radius){
    this.radius = radius;
    System.out.println("A constructor");
    }
   public static void main(String[] args){
   A a = new A(5);//当执行A a = new A(5);时,因为类A继承类B,所以先执行类B的构造函数,
                   //由于类A重写了B中的draw方法,所以执行类A中的draw,而类A还没有被初始化,
       //radius还没有被赋值,所以radius为默认值0.
   }
}
代码中的红体字为解释
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马