我贴出一段代码
public   class  Target  extends  Depend   {
    
      int  i  =   30 ;     public  Target()  {
        print();
        i  =   40 ;
        
     } 
      void  print()  {
            
            System.out.println( " Target=>  "   +  i);
     
       } 
    
     public   static   void  main(String[] args)   {
        
        System.out.println(new  Target().i);     } 
 

 
  class  Depend  {
    
     int  i  =   10 ;
    public  Depend()  {
        
        print();
        i  =   20 ;
    } 
     void  print()  {        System.out.println( " Depend=>  "   +  i);
    } 
    
} 运行结果是:
Target=>  0
Target=>  30
40
大家讨论 为什么会这样

解决方案 »

  1.   

    print()方法被重载了,是一个多态方法。
      

  2.   

    首先调用父类无参的构造方法,super()是隐藏的,但是一定会执行
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    public class Target extends Depend {
    int i = 30 ;
    public Target() {
    //super();---------首先调用父类的构造方法
    print();
    i = 40 ;
    }
    void print() {
    System.out.println( " Target=> " + i);

    public static void main(String[] args) {
    System.out.println(new Target().i);

    }
    class Depend {
    int i = 10 ;
    public Depend() {
    print();
    i = 20 ;
    }
    void print() {
    System.out.println( " Depend=> " + i);
    }
    }
      

  3.   

    Target=>  0
    这个挺头晕.
    算是自动初始化的值?
    刚开辟过空间,自动初始化为0?
    那个达人可以帮忙解释一下?
      

  4.   

    其实java并不是要等父类构造完了在构造子类的 
    子类方法覆盖父的方法,
    在构造方法里面最好只做初始化的工作
    不要调用方法
      

  5.   

    ========================================================================
    java技术交流,讨论java的技术细节和最新技术。欢迎中高级程序员加入讨论。QQ群:3001581(人员有限,不接收初学者,谅解)
      

  6.   

    首先调用父类无参的构造方法,这时的i都初始化是0。Target.i=0,Depend.i=0   然后Depend构造方法中有print(),但此时调用的确是Target中的print(),因为这时print()方法被重载了,又因为这时的Target.i的值还是0(Target.i=30还没有执行,只是Depend.i=10执行了),而Depend.i=10,所以输出Target=>  0,此后大家都明白吧,在这就不说了。
      

  7.   

    这的确是一个 fancy 的问题,我单步调试了好几遍,终于弄清楚了  :)我想,有 3 个关键点,搞清楚就好办了:1. 类实例化的时候,所有成员变量都有缺省值,int 型变量的缺省值为 0;2. 成员变量赋初值的操作是先于构造方法而执行的;3. 子类与父类中同名的成员变量,是两个独立的变量。在父类中为成员变量赋值,不会影响子类中的同名变量。也就是说,成员变量没有 override。所以,Target 构造的时候,先调用 Depend 的构造,后者调用的 print() 实际是 Target 中的 print(),打印出来的是 Target 中的 i,而这个 i 还没有赋值,所以打印出 0。
      

  8.   

    楼上说
    3. 子类与父类中同名的成员变量,是两个独立的变量。在父类中为成员变量赋值,不会影响子类中的同名变量。也就是说,成员变量没有 override。有点疑义.在下认为理解为:i指定的是target中的i而非depend中的i.target的print()换成如下.看结果可知.
    System.out.println( " Target=>  "   +  i);System.out.println( " Target super=>  "   +  super.i);
    看看?对子而言,有this与super之分.对外而言,无this与super之分.i依然被重载.
      

  9.   

    又有新疑问:
    如果我把int i = 30 ;这句注释掉  也就是没有成员变量的重载
    这时所有用到的都是父类Depend的成员变量i
    这时结果是:
    Target=>  10
    Target=>  20
    40
    按照10楼和11楼的说法就解释不通了。
    类实例化的时候是先初始化成员变量再调用构造方法。
    越来越糊涂了。
    哪位大虾  给正解
      

  10.   

    TO jackra(永恒の金条):“成员变量没有 override”这个结论是没错的。你试试下面这段代码,打印出来的东西是不一样的,也就是说,通过不同的类型访问同一个对象的同名成员变量,实际访问的是两个不同的变量:    Target t = new Target();
        Depend d = (Depend)t;
        System.out.println("t: " + t.i);
        System.out.println("d: " + d.i);
      

  11.   

    忘了,以前见过有人专门写的一篇文章说明。
    实际上是 int i= 30 ,这个赋值,与构造函数的问题。
    大致是这样的子类构造函数 如果没有显示调用父类的构造方法,会缺省的去掉用父类的不带参数的构造函数
    Target()所以会调用Depend(),由于Depend()他有调用Print(),print被重新写过了
    所以会调用子类的Print,此时子类的i并没有赋值,而是初始值0,父类调用完print后,返回到子类构造函数,子类继续调用Print,Print发现i没有初始化(注意这是类初始化后发现的),因此,调用赋值i=30,然后就打印出30,并且i=40 了,这应该就是
    Target=>  0
    Target=>  30至于最后的40 ,我没有明白。
      

  12.   

    没有明白,为什么输出40!虽然i=40,但是没有print语句呀。
    还有继承类本来就是保存一个父类的索引而言。,重写方法,也只是类似于C++的虚函数。
      

  13.   

    又有新疑问:
    如果我把int i = 30 ;这句注释掉  也就是没有成员变量的重载
    这时所有用到的都是父类Depend的成员变量i
    这时结果是:
    Target=>  10
    Target=>  20
    40
    按照10楼和11楼的说法就解释不通了。
    类实例化的时候是先初始化成员变量再调用构造方法。
    越来越糊涂了。
    哪位大虾  给正解这个疑问很简单,int i = 30 ;这句注释掉也就是说Target中没有i这个变量,也就不可能初始化值,语句System.out.println( " Target=>  "   +  i);只能上父类找这个i值,这是父类的i值是10,所以输出Target=>  10,因此10楼和11楼的说法是对的。
      

  14.   

    晕,没有看到主程序的print,不好意思,我总结下1.    设置成员的值为缺省的初始值 (0, false, null)
    2.    调用对象的构造函数 (但是还没有执行构造方法体)
    3.    调用父类的构造函数,如果父类的构造函数调用了其他函数,则
    须注意,如果该函数被子类重载,那么实际调用的是子类的相应函数,如果该函数没有重载,那么父类调用该函数。如果该函数使用了成语变量,那么需要先检查成员变量是否要赋值 ,(调用赋值 如i=30)
    4.    使用初始化程序和初始块初始化成员(调用赋值 如i=30)
    5.    执行构造方法体问题是第3步与第4步发生的。
      

  15.   

    构造方法的执行顺序是这样的:
      1.在对象的构造函数执行之前会先执行其父类的初始化.
      2.如果父类还有父类的话依次递归
      3.始化的过程是首先定义变量,如果没有初始化变量就赋一个默认值.
    上述问题是这样的当你在父的构造函数里调用的print其实是重载后的.是子类的方法.但这个时候i并没有定义(这个可以确定,不信自己可以有debug跟一下).不知道java为什么会输出0,也许是java的bug .当在子类的构造函数中调用print方法时,此时i 已定义.
    建议:构造函数只是初始化工作.不要在里面执行方法(用于初始化的方法除外),这是写程序的大忌.
      

  16.   

    System.out.println(new  Target().i);
    这句就是输出i的值的吧,所以会输出40。其他的print()方法输出的。