今天看到这样一篇文,是一道Java程序运行结果的问题,据有关专家调查,结果是98%的Java程序员都搞不懂,看了的确好奇怪,请大家也来看看,证实下是否属实,很疑惑... 问题:public class Parent 

 public void test() 
 {} public Parent() 
 {
  test();
 } public static void main(String[] args) 
 {
  new Child();
 }
}class Child extends Parent 
{
 private int instanceValue = 20;
 public void test() 
 {
  System.out.println("instance value is: " + instanceValue);
 }
}   各位先猜猜打印的结果是多少呢?为什么呢?

解决方案 »

  1.   

    ----------------------------------------------------------------  答案:下面是摘自本人编写的《Java就业培训教程》中的一段讲述,请大家注意第(4)步和第(5)步的讲解,调用完父类的构造方法后,接着才进行成员变量的显式初始化操作,上面代码中的private int instanceValue = 20;定义应看成两部分:第一部分是定义变量,第二部分是给变量赋值,变量定义位于父类构造方法之前,变量赋值位于父类构造方法之后。在父类的构造方法执行时,根据多态性,它会去调用子类中定义的test()方法,可是,这时候,子类中的成员变量还没执行显式初始化操作, 对于private int instanceValue = 20;定义,instanceValue 的值为默认的初始化值0,所以,这时候在test方法中打印出的值为0。  4.1.3子类对象的实例化过程  对于许多Java老手来说,子类对象的实例化过程也不见得非常清楚,你可能并不需要完全了解子类对象的实例化过程,但了解后还是有好处的。  对象中的成员变量的初始化是按下述步骤进行的:  (1)分配成员变量的存储空间并进行默认的初始化,就是用new关键字产生对象后,对类中的成员变量按第三章的表3.1中的对应关系对对象中的成员变量进行初始化赋值。   (2)绑定构造方法参数,就是new Person(实际参数列表)中所传递进的参数赋值给构造方法中的形式参数变量。  (3)如有this()调用,则调用相应的重载构造方法(被调用的重载构造方法又从步骤2开始执行这些流程),被调用的重载构造方法的执行流程结束后,回到当前构造方法,当前构造方法直接跳转到步骤(6)执行。(反正要去调用父类的构造函数,如果调用this,那么this指向的构造函数就会去调用父类的构造函数,我这个构造函数本身就不用再调用父类的构造函数了,如果没有调用this,那我这个构造函数就必须去调用父类的构造函数)  (4)如有没有this()调用,显式或隐式追溯调用父类的构造方法(一直到Object类为止,Object是所有Java类的最顶层父类,/*在本章后面部分有详细讲解*/),父类的构造方法又从步骤2开始对父类执行这些流程,父类的构造方法的执行流程结束后,回到当前构造方法,当前构造方法继续往下执行。  (5)进行成员变量的显式初始化操作,也就是执行在定义成员变量时就对其进行赋值的语句,如:public Student extends Person
    {
     String school = ”it315”;// 显式初始化
     ……
    }   将“it315”赋值给school成员变量。  (6)执行当前构造方法的方法体中的程序代码,如: public Student extends Person
    {
     public Student(String name,int age,String school)
     { 
      super(name,age);
      this.school = school;
     }

    转www.javajia.com
      

  2.   

    这个问题在practice java中有详细的介绍的。
      

  3.   

    写成两句就明白了
    int instanceValue; // 构造之前执行,这时没有赋值为0
    instanceValue= 20;  //构造之后执行
      

  4.   

    可是,父类的构造函数里面并没有打印语句啊?
    public void test() {}
    是我理解有问题,还是......
      

  5.   

    看过另外一片文章是这样说的,但是讲的不是很细致:(执行顺序)父类静态初时化块->子类静态初始化块->父类初始化块->父类构造函数->子类初始化块->子类构造函数
      

  6.   

    关键概念:“部分初始化(Partially Initialization)”
      

  7.   

    生成子类对象
    构造过程如下:
    父类成员初始化
    父类构造器
    子类成员初始化
    子类构造器啊,
    new Child();会先去初始化父类成员,调用test()方法,但是此方法子类实现了override,所以执行子类中的test()方法,此时子类字段未初始化,系统自动初始化为0。
    整个初始化过程我还是明白。开始有点模糊的是父类中的test方法为什么执行的是子类?
      

  8.   

    instance value is:20初始化是要调用父类的默认构造函数
      

  9.   

    不等于20,为0奇怪为什么执行的是子类的test()啊?初始化父类的时候也会被overriode?
      

  10.   

    经过上机验证,输入 java Parent 
    结果是什么也没有显示,所以根本就没有执行println 语句!
    测试环境: XP2+JAVA SDK5。0!
      

  11.   

    建议去看think in java 第三版 第四章初始化与清理。必有收获!
      

  12.   

    补充一句,yupengfei_110() 的答案我认为才是正确的。
     
    经过上机验证,输入 java Parent 
    结果是什么也没有显示,所以根本就没有执行println 语句!
    测试环境: XP2+JAVA SDK5。0!
      

  13.   

    原因是子类的test() 方法没有被调用过
      

  14.   

    instance value is: 0XP2 + j2sdk1.4.2_08 + Eclipse3.2.1
      

  15.   


    正确答案是:instance value is: 0对不起,上次我输入代码Child 时少输了extends Parent,所以才造成什么也没有输出!!
      

  16.   

    TO mouze() ( ) 
    因为你创建的对象是Child类的不是Parent的
      

  17.   

    下面给出一个我认为比较权威的答案。
    首先,有一点肯定的是Java会为没有构造函数的类家一个没有参数的构造函数。
    其次,构造函数的第一个语句不是super(...)的话,Java会为它加一个默认的super();调用
    第三,我又新建了一个Runner雷,专门负责运行。以便独立观察Parent,Child的行为。
    第四,我在Parent类里也加了静态的成员,并对各类稍作修改。
    第五,执行顺序见代码注释,JDK1.4.2_13public class Runner {
        public static void main(String[] args) {
            new Child();     //1
        }
    }class Parent {
        public static int PARENT_STATIC;
        {
            PARENT_STATIC = 0;  //3
        }    public void test() {
        }    public Parent() {
            test(); //4
        }}class Child extends Parent {
        public int CHILD_STATIC;    {
            CHILD_STATIC = 0;  //6
        }    public Child() {
            super();    //2
        }    public void test() {
            System.out.println("instance value is: " + CHILD_STATIC);  //5
        }
    }
      

  18.   

    如果调用考过SCJP的话,这个问题应该不难。我把几个关键点在罗列一下:1、有一点肯定的是Java会为没有构造函数的类加一个没有参数的构造函数。所以,做题的时候,自己加上一个吧。
    2、构造函数的第一个语句不是super(...)的话,Java会为它加一个默认的super();的调用,所以,做题的时候自己加上一个吧。
    3、类的块语句,会在构造函数的super调用后执行。切记,不是static块,static块在加载类的时候运行。若要彻底明白这道题,看看下面的代码:public class Runner {
        public static void main(String[] args) {
            new Child();     //1
        }
    }class Parent {
        public static int PARENT_STATIC;
        static {
            PARENT_STATIC = 0;  //2
        }    public int parentVar;
        {
            parentVar = 0; //6
        }    public void test() {
        }    public Parent() {
            super();  //5
            test();   //7
        }}class Child extends Parent {
        public static int CHILD_STATIC;    static {
            CHILD_STATIC = 0;  //3
        }    public int childVar;    {
            childVar = 0; //9
        }    public Child() {
            super();    //4
        }    public void test() {
            System.out.println("instance value is: " + CHILD_STATIC);  //8
        }
    }
      

  19.   

    大家好:
      我觉得int instanceValue = 20;定义应看成两部分:第一部分是定义变量 变量默认为0,第二部分是给变量赋值 因为变量在内存中先声明区域 再初始化分配大小
      首先是有2个类 又有继承 从main()进 先调用父类的构造方法 我相信大家都知道把
        再就是构造方法里调用子类的text()方法 多太 重写 
        再打印为0
     希望高手指点下 我也是刚学 谢谢
      

  20.   

    大家好:
      我觉得int instanceValue = 20;定义应看成两部分:第一部分是定义变量 变量默认为0,第二部分是给变量赋值 因为变量在内存中先声明区域 再初始化分配大小
      首先是有2个类 又有继承 从main()进 先调用父类的构造方法 我相信大家都知道把
        再就是构造方法里调用子类的text()方法 因为根据 多态 重写 
        再打印为0
     希望高手指点下 我也是刚学 谢谢
      

  21.   

    JAVA技术群!愿意的加!36310034!!!!
    JAVA技术群!愿意的加!36310034!!!!
    JAVA技术群!愿意的加!36310034!!!!
    vJAVA技术群!愿意的加!36310034!!!!
    JAVA技术群!愿意的加!36310034!!!!
      

  22.   

    我是这样理解的:由于多态性,new Chlid()是父类的实例化,所以直接调用test()方法,此过程在为instanceValue赋值之前,由于基本类型的变量默认为0,所以结果是0;
      

  23.   

    haha 
    被人家骗了吧!补充一句,yupengfei_110() 的答案我认为才是正确的。
     
    经过上机验证,输入 java Parent 
    结果是什么也没有显示,所以根本就没有执行println 语句!
    测试环境: XP2+JAVA SDK5。0!
      

  24.   

    又学到了一点东西,thank you
      

  25.   

    什么都没有打印
    执行父类的test()方法
    我认为是这样,没有尝试
      

  26.   

    public class C
    {
    public void test(){
    }

    public static void main(String [] args)
    {
    new B();
    }
    }class B extends C
    {
    int num=20;

    public void test()
    {
    System.out.println("num : "+num);
    }
    }
    没有输出
      

  27.   

    public class C
    {
    public void test(){
    }

    public C()
    {
    test();
    }

    public static void main(String [] args)
    {
    new B();
    }
    }class B extends C
    {
    int num=20;

    public void test()
    {
    System.out.println("num : "+num);
    }
    }num : 0刚才少打了父类构造函数
      

  28.   

    创建子类之前要先创建父类,在创建父类的时候,子类还不存在,父类的构造函数调用的是自己的TEST方法,这个方法什么都不做,所以什么都不会打出来,然后再创建子类,子类的构造方法是默认构造方法,里面什么也没有,所以也什么也不做,最后的结果是什么也没有打印出来的。回答完毕!
      

  29.   

    public class Parent 

    public void test(){
    System.out.println("Parent.test()");
    }

    public Parent()
    {
    System.out.println("Parent");
    test();
    }

    public static void main(String[] args){
    System.out.println("main");
    new Child();
    }
    }
    public class Child extends Parent {
    public Child(){
    System.out.println("Child");
    }
    private int instanceValue = 20;

    public void test() 
    {
    System.out.println("Chile.test()");
    System.out.println("instance value is: " + instanceValue);
    }}
    我加了以下打印,输出结果为:
    main
    Parent
    Chile.test()
    instance value is: 0
    Child
      

  30.   

    看看这样是不是有点提示:
    public class Parent
    {
      public void test() {}  public Parent() {
        test();
      }  public static void main(String[] args) {
        Child child=new Child();
    child.test();
      }
    }class Child extends Parent {
      private int instanceValue = 20;
      public void test() {
        System.out.println("instance value is: " + instanceValue);
      }
    }
      

  31.   

    晕死了,看来大部分人都不会啊,知其一不知其二
    是这样的 其实很简单大家反编译以下class 文件看生成的字节码就很清楚了
    首先 new Child()  会生成2条语句 :
    new   #20  <Class Child>
    invokespecial   #21  <Method void Child()>
    先创建对象顺序 Object->Parent->Child 这个时候根据JAVA的规则赋默认值比如int 类型为0
    然后才调用 够造函数
    这样大家就明白多了吧。
    其实够造函数和其他的普通方法没有什么区别,你把他当作普通的方法一样。只不过new 以后虚拟机会自动调用它而已。
    写成以下的伪代码大家
       class Parent{
         public void test() {}     public void Parent() {//编译器会转换够找函数为这样
              test();
            }
       }
       class Child extends Parent {//其实是这样
      private int instanceValue = 20;
      public void Child(){
        //调用Parent() ;方法
        instanceValue=20;
      };
      public void test() {
        System.out.println("instance value is: " + instanceValue);
      }
    }
    new Child()  转换为 new child; 
                        调用方法Child();一直到执行结束
    至于静态语句 只在第一次主动调用的时候执行。大家要记住 创建对象与初始化是2个步骤
      

  32.   

    按照java构造对象的顺序,先父后子。
    很显然,在构造parent的时候,test没有具体实现;而child的无参构造没有重写,所以child的test没有作用(你要是用eclipse会发现此test有一条黄线标示,说明没有被调用。。)
      

  33.   


    java Parent
    会先运行main,
    new Child()初始化Child
    首先声明和初始所有的final域
    然后声明其他的域
    然后调用构造函数
    因为Child没有明确构造函数,它将调用父类的默认构造函数
    这时候,child其实变为
    class Child
    {
     private int indstancdValue=20;
     public Child
     {
      test();
     }
     public void test
     {
      System.out.println("instanceValue="+instanceValue);
     }
    }
    child的构造函数直接调用child的test方法
    这时候因为只是声明了instanceValue,它会被赋予默认值,数字为0
    然后调用println方法打印
    然后才执行instanceValue=20可以在main中初始化一个child实例,然后再调用其test方法
    结果将打印为20一般情况下,如果想在初始化化之间就给变量赋值
    可以声明其为final
    但这样就无法再修改其值了例如如果改为
    final int instanceValue=20;
    打印结果将会是20
      

  34.   

    这个问题的原形是在《java编程语言》中,哪一版都有,讲得很详细啊
      

  35.   

    现在还看不懂,马上准备自学JAVA,希望各位高手能随时指点.
      

  36.   

    我一般很少调用Field,即使是私有的也用getter方法
      

  37.   

    $ zz╭ ╮╭ ﹌╮.       $
    $   z(o-.-o)(o-.-o) .      $
    $ ┏~﹊︸ ̄~﹊︸ ̄~┓      $
    $ IT者-IT开发者的网站--    $
    $ 10万篇技术资料--天天更新 $
    $ -----www.itzhe.cn-----   $
      

  38.   

    在eclipse里面没有发现test那句话有红色的提示线
      

  39.   

    首先在其他任何事情没有发生之前 分配对象的内存空间初始化为二进制0
    new Child();//调用子类首先先调用父类的构造函数 这时调用的test()Child的构造函数还没有被调用 所以输出为0
    public class Parent
    {
    public void test(){}
    public Parent()
    {
    test();
    }
    public static void main(String[] args)
    {
    new Child();//调用子类首先先调用父类的构造函数
    }
    }class Child extends Parent 
    {
        private int instanceValue = 20;
        public void test()
        {
        System.out.println("instance value is: " + instanceValue);
        }
    }
      

  40.   

    从本质上理解,我贴出字节码来
    //Parent的字节码
    public class Parent extends java.lang.Object{
    public void test();
      Code:
       0:   returnpublic Parent();
      Code:
       0:   aload_0
       1:   invokespecial   #13; //Method java/lang/Object."<init>":()V
       4:   aload_0
       5:   invokevirtual   #15; //Method test:()V //看这个invokevirtual指令会多态调用,再转到Child的 test()方法去
       8:   returnpublic static void main(java.lang.String[]);
      Code:
       0:   new     #19; //class Child
       3:   invokespecial   #21; //Method Child."<init>":()V
       6:   return}//Child的字节码
    class Child extends Parent{
    Child();
      Code:
       0:   aload_0
       1:   invokespecial   #10; //Method Parent."<init>":()V
       4:   aload_0
       5:   bipush  20     //构造Parent的时候,常量20还没有压到栈里
       7:   putfield        #12; //Field instanceValue:I
       10:  returnpublic void test();
      Code:
       0:   getstatic       #19; //Field java/lang/System.out:Ljava/io/PrintStream;
       3:   new     #25; //class java/lang/StringBuilder
       6:   dup
       7:   ldc     #27; //String instance value is:
       9:   invokespecial   #29; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
       12:  aload_0        //整数零赋值为 instanceValue
       13:  getfield        #12; //Field instanceValue:I //取到的是0
       16:  invokevirtual   #32; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
       19:  invokevirtual   #36; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
       22:  invokevirtual   #40; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
       25:  return}可以看出在 new Child()->Parent.test()->Child.test()的过程中Child的构造函数并没有执行,所有instanceValue是一个默认值,Parent构造之后才去构造Child(),会给instanceValue赋上20
    Parent和Child的关系是:
    Child isA Parent
    Child hasA Parent