我看了一下你的原代码:
abstract class Glyph {
abstract void draw();
Glyph() {
System.out.println("Glyph() before draw()");
draw();
System.out.println("Glyph() after draw()");
}
}class RoundGlyph extends Glyph {
int radius = 1;
RoundGlyph(int r) {
radius = r;
System.out.println("RoundGlyph.RoundGlyph(), radius = "+ radius);
}
void draw() {
System.out.println("RoundGlyph.draw(), radius = " + radius);
}
}public class PolyConstructors {
public static void main(String[] args) {
new RoundGlyph(5);
}
}
在你的MAIN方法中,有new RoundGlyph(5);jvm在执行这条语句的时候,在执行自己的构造方法RoundGlyph(int r) {}之前,由于继承关系先执行父类的无参数的构造方法打印出第一条语句Glyph() before draw(),在调用draw()方法,打印出RoundGlyph.draw(), radius = 0,然后再执行     System.out.println("Glyph() after draw()");打印出Glyph() after draw(),最后调用自身的RoundGlyph(int r){}打印出 RoundGlyph.RoundGlyph(), radius = 5。这就是程序的整个流程。  你问结果输出第2行为什么不是RoundGlyph.draw(), radius = 1?我们可以这样认为:这里的radius是一个局部变量,如果想让它为1的话,必须是
this.radius,这样才能调用类的属性。

解决方案 »

  1.   

    不知道你懂了没有。如果你还不明白,可给我发邮件:[email protected]
      

  2.   

    abstract class Glyph {
    abstract void draw();
    Glyph() {
    System.out.println("Glyph() before draw()");
    draw();
    System.out.println("Glyph() after draw()");
    }
    }class RoundGlyph extends Glyph {
    int radius = 1;
    RoundGlyph(int r) {
    radius = r;
    System.out.println("RoundGlyph.RoundGlyph(), radius = "+ radius);
    }
    void draw() {
    System.out.println("RoundGlyph.draw(), radius = " + radius);
    }
    }public class PolyConstructors {
    public static void main(String[] args) {
    new RoundGlyph(5);
    }
    }再补充:
    其实上边这段代码跟下面是一样的效果:
    abstract class Glyph {
    abstract void draw();
    Glyph() {
    System.out.println("Glyph() before draw()");
    draw();
    System.out.println("Glyph() after draw()");
    }
    }class RoundGlyph extends Glyph {
    int radius = 1;
             RoundGlyph(){
    System.out.println("Glyph() before draw()");
    draw();
    System.out.println("Glyph() after draw()");
     } RoundGlyph(int r) {
    radius = r;
    System.out.println("RoundGlyph.RoundGlyph(), radius = "+ radius);
    }
    void draw() {
    System.out.println("RoundGlyph.draw(), radius = " + radius);
    }
    }public class PolyConstructors {
    public static void main(String[] args) {
    new RoundGlyph(5);
    }
    }
      

  3.   

    我觉得是这样的:
    jvm在装入类的时候,并未对变量进行初始化。而在字节代码执行之前进行的初始化,只是调用静态变量和静态初始化器进行初始化,例如,定义 static int radius = 1;则运行结果就与现在的不同了,这是因为radius为static,所以就先初始化了。
    而上面这段代码,是先执行父类Glyph的构造方法,并未涉及到对radius的初始化,所以此时它的值还是默认的初始值0。
    也可以这样理解:在字节代码中的执行顺序,Glyph()是在int radius = 1所对应的字节代码之前的。
    一家之言,仅供参考。
      

  4.   

    BenLadeng5225(Ladeng) 的话听起来是有点道理但是加了this还是和原来的结果一样
      

  5.   

    那是因为你将Glyph定义为抽象类,抽象类的机制就是:使用它的时候必须要继承抽象类后才能被实例化。而原先的构造器也会被继承下来。也就是说,在你的RoundGlyph类里的构造器是在Glyph里定义的Glyph(),所以你在main()里实例化的RoundGlyph类时应首先执行RoundGlyph的构造器,也就是在Glyph里定义的Glyph()方法(其中的draw()方法已经在RoundGlyph类里面定义了,应此你可以把抽象类机制中的继承看成是将抽象类完善的结果)RoundGlyph类实例化的时候已经将你在Glyph()中所写的构造器部分执行过了,形成了输出的前三行,而你在RoundGlyph类中初始化的radius=1并没有被用到。另外,由于你在实例化的时候,构造器中并没有初始化radius,java编译器就自动给他初始化为“0”了。
      

  6.   

    调用过程是:
    父类的变量定义和初始化
    父类的构造方法
    子类的变量定义和初始化
    子类的构造方法如果在父类的构造中调用需要在子类中初始化的变量时,实际上那时候这个变量还没有初始化。对于 int 型来说,结果就是 0
      

  7.   

    你们看看这段代码:/*
     * @file Test.java
     * @author Fancy
     */class TestBase {    int b = Toolkit.test("TestBase");    void test() {
        }    TestBase() {
            System.out.println("TestBase Constructor");
            test();
        }}public class Test extends TestBase {    int x = Toolkit.test("Test");    void test() {
            System.out.println("Test.test, x = " + x);
        }    Test() {
            System.out.println("Test Constructor");
        }    public static void main(String[] args) {
            new Test();
        }
    }
    class Toolkit {
        static int test(String s) {
            System.out.println("Toolkit.test(), s = " + s);
            return 1;
        }
    }
    运行结果Toolkit.test(), s = TestBase
    TestBase Constructor
    Test.test, x = 0
    Toolkit.test(), s = Test
    Test Constructor这就说明了我上面的说法,再抄一次:调用过程是:
    父类的变量定义和初始化
    父类的构造方法
    子类的变量定义和初始化
    子类的构造方法如果在父类的构造中调用需要在子类中初始化的变量时,实际上那时候这个变量还没有初始化。对于 int 型来说,结果就是 0
      

  8.   

    楼上几位说的都有道理,不知  Iforgot(清风雨)有什么观点?大家共同研究!
      

  9.   

    先父类初始化,再子类初始化
    在调用父类构造为函数时,i没有被付初值1,而只是int型默认初始化为0
      

  10.   

    我忽然觉得有点明白了,当然分会照给的!我觉得还是版主比较正确。大家看看是不是,Java的对象变量(就是非类变量static的变量,一般书上有叫本地变量的、但容易和方法中的本地变量混淆,所以自己胡取了一个名字。:))
    声明同时付值实际上实在构造器调用完毕付的值呢?猜想,我回去试试看。
      

  11.   

    我看看 iamfancy(边城狂人) 的,回去试一下。谢谢各位啊!:)
      

  12.   

    在Thinking in Java里面有详细的叙述,当你初始化class RoundGlyph的
    时候,由于关键字extends的存在,知道有class Glyph的存在,于是载入
    class Glyph。在实例化class Glyph之前,因为有抽象方法的存在
    于是调用子类的方法,这时候,还没有给i赋值,所以是0
    后面都很简单,我就不说了
      

  13.   

    我看过了,我的猜测是错的。大家说的都比较有道理,但是我不明白,为什么变量定义被解析了,可是付值却没解析,而是等到万事具备才解析。实际调用好像是这样,和各位说的基本一致。
    new对象时,解析父类并调用相应的构造器。也就是说构造最上层父类对象属性,第2层父类对象属性,...最后是本对象属性,构造出对象。但是在构造父类对象(属性)时他调用本对象函数使用本对象的局部变量,但那时还没解析啊,或者算解析了,为什么不是一并负值呢?尽请指教,错误和思路不当之处请指正。:)
      

  14.   

    我的意思也就是说能够使用radius说明声明语句被执行了,但是为什么他的付值却没执行呢?应该是一同的(当然如果这样可能会出现其他问题,暂不考虑)。
    总觉得应该声明和付值一起才是,这里却不是这样,难到是解析了所有的声明后才付值?我也去试试看。要是被也推翻了,那就不知怎么解释了。
      

  15.   

    abstract class Glyph {
    abstract void draw();
    Glyph() {
    System.out.println("Glyph() before draw()");
    draw();
    System.out.println("Glyph() after draw()");
    }
    }class RoundGlyph extends Glyph {
    int radius = 1;
    RoundGlyph(int r) {
        draw();//这里调用draw,你看看输出就有启发了。
    radius = r;
    System.out.println("RoundGlyph.RoundGlyph(), radius = "+ radius);
    }
    void draw() {
    System.out.println("RoundGlyph.draw(), radius = " + radius);
    }
    }public class PolyConstructors {
    public static void main(String[] args) {
    RoundGlyph a= new RoundGlyph(5);

    }
    }
    第2行没有输出 radius=1,是因为,draw是在父类里面调用的,这时int radius = 1;还没有被初始化,而int型的变量在未被初始化时,默认值是零,假如你在RoundGlyph 里面调用,就不一样了,因为当你执行到RoundGlyph 类里面是,静态变量和成员变量都被初始化了,说仪输出为1。就这么简单,不知道我说的你明白否???
      

  16.   

    只是你不知道代码的执行顺序摆了,懂得了执行的顺序就知道结果了,
    这些在SCJP上说得很清楚,你多看看SCJP就OK了。
      

  17.   

    wjmmml(笑着悲伤) ,确实不明白,我不明白,声明有了赋值却没有,你能在父类通过某种方法使用,说明声明了,要不怎么用,可赋值却没有,如果你不用父类间接调用,声明和负值还是都会执行的。不知道有没有人能帮我解答啊!我需要的不简简只是这个表面啊,大家帮忙再看看。:)
      

  18.   

    这是一个多态,继承和构造顺序的问题,充分体现了OOP的特点..
    public static void main(String[] args) {
    new RoundGlyph(5);
    }
    中1首先构在父类
      2执行父类的构造函数,输出第一行,执行draw(),由于是在子类中写的main函数,并且父类是抽象函数,所以执行子类的draw的具体方法,但此时还没轮到子类RoundGlyph去给自己的成员变量radius去赋值为1,所以用默认的出使值0,就有了那个结果,让后在执行下一行输出
     3让后构造子类RoundGlyph,此时就为1了..
    具体再说里面还有好多细节...
      

  19.   

    "由于是在子类中写的main函数"这句我更正,是一个其他类中写的main函数.意思就是说这两个class文件已经存在了的前提下,运行这个.
      

  20.   

    因为super()语句默认在子构造函数的第一行,那时候还没执行
    radius = r;
    radius没有系统初始为0