黑马程序员技术交流社区

标题: 晕死了 [打印本页]

作者: 郑强强    时间: 2012-4-10 10:25
标题: 晕死了
Java代码  
class Depend{   
    int i = 10;   
    public Depend(){   
        print();   
        i = 20;   
    }   
  
    void print(){   
        System.out.println("Depend=> " + i);   
    }   
}   
  
  
public class Qdb extends Depend{   
    int i = 30;   
    public Qdb(){   
        print();   
        super.print();   
        i = 40;   
    }   
  
    void print(){   
        System.out.println("Target=> " + i);   
    }   
  
    public static void main(String[] args){   
        new Qdb();   
    }   
}  

其结果是:

Target=> 0
Target=> 30
Depend=> 20

哪位哥哥可以通俗的讲一下啊,这个具体的过程,特别是子类和 父类的成员变那部分
作者: 宋蕈    时间: 2012-4-10 10:50
它的调用流程大概是:
当你调用子类的构造函数时,它会自动的调用父类的无参构造函数,
接受,你调用了print() 方法,这里明显是调用了 子类自己的print()方法, 因为,子类覆写了print()方法
然后,又是 执行到super.print()时,这个当然就是调用父类的print()方法了。
作者: 黑马老兵    时间: 2012-4-10 10:53
你这个程序也就是对子类对象进行初始化的过程。
1.首先,初始化父类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化;
2.然后,初始化子类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化;
3.其次,初始化父类的普通成员变量和代码块,在执行父类的构造方法;
4.最后,初始化子类的普通成员变量和代码块,在执行子类的构造方法;
最后,给你个例子吧。你运行着帮助理解。
class Super{
        public static int a ;
        private int b ;
       
        static{
                System.out.println("此时a的值为:" + a) ;
                a = 10 ;
        }
        public Super(){
                System.out.println("此时a的值为:" + a) ;
                System.out.println("此时b的值为:" + b) ;
                b = 20 ;
        }
        {
                System.out.println("此时b的值为:" + b);
                b = 30 ;
        }
}
class Sub extends Super{
        public static int aa ;
        private int bb ;
       
        static{
                System.out.println("此时aa的值为:" + aa) ;
                aa = 10 ;
        }
        public Sub(){
                System.out.println("此时aa的值为:" + aa) ;
                System.out.println("此时bb的值为:" + bb) ;
                bb = 20 ;
        }
        {
                System.out.println("此时bb的值为:" + bb);               
                bb = 30 ;
        }
}
public class ConstructorTest {
        public static void main(String[] args) {
                new Sub() ;
        }
}
作者: 黄或俊    时间: 2012-4-10 11:05
继承总结:
1、同名的实例方法被覆盖 ,同名的静态方法被隐藏
2、隐藏和覆盖的区别在于,子类对象转换成父类对象后,能够访问父类被隐藏的变量和方法,而不能访问父类被覆盖的方法
3、如果需要访问父类被隐藏的实例变量,加上super就好了
作者: 王硕'    时间: 2012-4-10 15:15
耿世玉 发表于 2012-4-10 10:53
你这个程序也就是对子类对象进行初始化的过程。
1.首先,初始化父类中的静态成员变量和静态代码块,按照在 ...
  1. class Super{
  2.         public static int a=1;
  3.         private int b=2;
  4.         
  5.         static{
  6.                 System.out.println("此时a的值为:" + a) ;
  7.                 a = 10 ;
  8.         }
  9.         public Super(){
  10.                 System.out.println("此时a的值为:" + a) ;
  11.                 System.out.println("此时b的值为:" + b) ;
  12.                 b = 20 ;
  13.         }
  14.         {
  15.                 System.out.println("此时b的值为:" + b);
  16.                 b = 30 ;
  17.         }
  18. }
  19. class Sub extends Super{
  20.         public static int aa=3;
  21.         private int bb=4;
  22.         
  23.         static{
  24.                 System.out.println("此时aa的值为:" + aa) ;
  25.                 aa = 10 ;
  26.         }
  27.         public Sub(){
  28.                 System.out.println("此时aa的值为:" + aa) ;
  29.                 System.out.println("此时bb的值为:" + bb) ;
  30.                 bb = 20 ;
  31.         }
  32.         {
  33.                 System.out.println("此时bb的值为:" + bb);               
  34.                 bb = 30 ;
  35.         }
  36. }
  37. class Test {
  38.         public static void main(String[] args) {
  39.                 new Sub() ;
  40.         }
  41. }
复制代码
你的例子非常好,为什么确认显示初始化排在什么位置,修改了下初值,结果发现显示初始化先于构造代码快和构造函数,所以我很奇怪为什么楼主的例子里Target=>0会先出现,而且是0?
作者: 黑马老兵    时间: 2012-4-10 15:53
王硕' 发表于 2012-4-10 15:15
你的例子非常好,为什么确认显示初始化排在什么位置,修改了下初值,结果发现显示初始化先于构造代码快和 ...

我理解的是System.out.println("Target=> " + i);   这句话复写了父类的方法,先执行了。但变量i还是子类中的i这个时候子类中的常量还没被赋值,只是随着对象的建立被jvm默认为0.不知道这样说你能明白不?

作者: 郑强强    时间: 2012-4-10 15:56
耿世玉 发表于 2012-4-10 10:53
你这个程序也就是对子类对象进行初始化的过程。
1.首先,初始化父类中的静态成员变量和静态代码块,按照在 ...

你这个程序也就是对子类对象进行初始化的过程。
1.首先,初始化父类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化;
2.然后,初始化子类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化;
3.其次,初始化父类的普通成员变量和代码块,在执行父类的构造方法;
4.最后,初始化子类的普通成员变量和代码块,在执行子类的构造方法;

按照你的说法,在执行父类的构造函数时,那个父类中print(),打印的应该是depend=10才对啊,为什么运行结果却是那样呢


作者: 黑马老兵    时间: 2012-4-10 17:08
郑强强 发表于 2012-4-10 15:56
你这个程序也就是对子类对象进行初始化的过程。
1.首先,初始化父类中的静态成员变量和静态代码块,按照 ...

他被子类中的复写了啊 。
作者: 黑马老兵    时间: 2012-4-10 17:09
耿世玉 发表于 2012-4-10 17:08
他被子类中的复写了啊 。

额。。。你说的:'(我也晕了。。。
作者: 王硕'    时间: 2012-4-11 09:54
耿世玉 发表于 2012-4-10 17:09
额。。。你说的我也晕了。。。
  1. class Depend{   
  2.     int i = 10;
  3.    
  4.     {
  5.                     System.out.println("父类构造代码块");
  6.                     System.out.println(i);
  7.     }
  8.       
  9.     public Depend(){
  10.                     System.out.println("父类构造函数");     
  11.         print();   
  12.         i = 20;   
  13.     }   
  14.   
  15.     void print(){   
  16.         System.out.println("Depend=> " + i);   
  17.     }   
  18. }   
  19.   
  20.   
  21. class Qdb extends Depend{   
  22.     int i = 30;   
  23.     public Qdb(){
  24.                     //super();
  25.                     System.out.println("子类构造函数");   
  26.         print();   
  27.         super.print();   
  28.         i = 40;   
  29.     }   
  30.   
  31.           {
  32.                     System.out.println("子类构造代码块");
  33.                     System.out.println(i);
  34.     }
  35.    
  36.     void print(){   
  37.         System.out.println("Target=> " + i);   
  38.     }   
  39.   
  40.     public static void main(String[] args){   
  41.         new Qdb();   
  42.     }   
  43. }
复制代码

作者: 王硕'    时间: 2012-4-11 10:35
耿世玉 发表于 2012-4-10 17:09
额。。。你说的我也晕了。。。

其实从一开始你就没错,老毕的视频里没讲过子类继承父类的初始化过程。当时只在静态的时候讲过初始化,而且都没讲方法区的内容,所以我一直按那个思维思考。
另外还有一点的就是过分在意子类构造函数的第一行是父类构造函数,就认为父类构造函数执行完就去执行子类构造函数了,而子类显示初始化优先于子类构造函数,所以就产生了“先有鸡还是先有蛋”的崩溃思想。
你列出的顺序很清楚:父类初始化完,再去初始化子类的非静态代码,包括非静态成员变量,非静态方法,构造代码块,和构造函数等。
父类的构造函数执行时,子类还没显示初始化了,当然结果是null。 为什么调用父类的构造方法,而父类的构造方法又去调用成员方法,为什么却用的是子类的方法?
这个问题光记结果可能更疑问,我觉得应该这样理解,你new的是子类的对象,我们知道每一个非静态方法中都有一个隐式的引用this,当你调用一个非静态方法时,这个this就指向了调用它的对象。当super方法调用print方法时,其实是指向的子类对象,而这个方法又被子类覆盖过,所以用的就是子类方法。
其实,你的那个步骤还不是非常详细,具体到网上搜吧, 从类加载进来直到一个对象new出来的整个过程。

未命名.JPG (10.02 KB, 下载次数: 39)

未命名.JPG





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2