《Java编程思想》学习02:继承类的初始化加载顺序分析

 

本文根据源码实例,分析继承类初始化的加载顺序;

参考《Java编程思想》第十章

 

思路:创建三个类动物Animal类、狗狗Dog类、哈士奇Huskie类,每个类中有一个非静态变量和无参构造函数,且Huskie类继承Dog类,Dog类继承Animal类;然后实例化一个Huskie类对象,根据输出的日志确认加载顺序

 

 

源码

Animal类

package com.tyj.study.thinkinjava.chapter8;

/* *
 *@Description:
 *@Author:TYJ
 *@Date: create in  2019/7/10 8:59
 */

public class Animal {

    private Double weight = getWeight();

    private Double getWeight() {
        System.out.println("i am Animal getWeight method");
        return new Double(1.0);
    }

    public void eat(){
        System.out.println("i am Animal eat method");
    }

    public Animal() {
        System.out.println("i am animal constructor");
        eat();
    }

    public static void main(String[] args) {
        Animal animal = new Animal();
        /**
         日志输出:
             i am Animal getWeight method
             i am animal constructor
             i am Animal eat method
         */
    }

}

Dog类

package com.tyj.study.thinkinjava.chapter8;

/* *
 *@Description:
 *@Author:TYJ
 *@Date: create in  2019/7/10 9:00
 */

public class Dog extends  Animal{

    private int legNum = getLegNum();
    private String food = new String("meat");

    private int getLegNum(){
        System.out.println("i am Dog getLegNum method");
        return 4;
    }

    public void eat(){
        System.out.println("i am Dog eat method. dog eat " + food);
    }
    public Dog() {
        System.out.println("i am Dog constructor");
    }

    public static void main(String[] args) {
        Dog dog = new Dog();
        /**
         日志输出:
             i am Animal getWeight method
             i am animal constructor
             i am Dog eat method. dog eat null
             i am Dog getLegNum method
             i am Dog constructor
         */
    }
}

 

 

Huskie类

 

package com.tyj.study.thinkinjava.chapter8;

/* *
 *@Description:
 *@Author:TYJ
 *@Date: create in  2019/7/10 9:00
 */

public class Huskie extends  Dog{

    private Boolean isStupid = judgeIQ();
    private Boolean isLovely = judgeLovely();
    private Boolean judgeIQ(){
        System.out.println("i am Huskie judgeIQ method");
        return true;
    }
    private Boolean judgeLovely(){
        System.out.println("i am Huskie judgeLovely method");
        return true;
    }

    public Huskie() {
        System.out.println("i am Huskie constructor");
    }

    public static void main(String[] args) {
        Huskie huskie= new Huskie();
        /**
         日志输出:
             i am Animal getWeight method
             i am animal constructor
             i am Dog eat method. dog eat null
             i am Dog getLegNum method
             i am Dog constructor
             i am Huskie judgeIQ method
             i am Huskie judgeLovely method
             i am Huskie constructor
         */
    }
}

 

 

分析

  1-分析Animal类的main方法,可以确认,实例化一个普通类,会先初始化变量,再调用构造函数;(更具体的分析,请参考本人上一篇博客:《Java编程思想》学习01:普通类的初始化加载顺序分析》

  2-分析Huskie类的main方法,实例化一个子类,会递归找到最最上层的父类,然后按照继承的顺序初始化,本案例中,会依次初始化Animal类,Dog类,Huskie类;并且在舒适化每一个类的时候,先初始化变量,在调用构造器;

  3-分析Dog类的main方法,输出了"i am Dog eat method. dog eat null",原因是因为Dog类实例化是,调用了父类Animal类的构造器方法,执行了eat();但因为Dog类重写了eat()方法,所以Animal类的构造器调用的是Dog类的eat()方法,但此时Dog类还没有被初始化,所以此时Dog类的food变量的值是null;所以输出"i am Dog eat method. dog eat null";

 

总结

  1-实例化一个普通类,会先初始化变量,再调用构造函数;

  2-实例化一个有继承关系的子类,会递归找到最上层的父类,然后按照继承的顺序依次初始化每一个类;

  3-实例化时,如果父类的构造器调用了被子类重写的方法,而子类方法有引用了子类的成员变量,则可能会出现因为成员变量未被初始化就被使用的情况;

  4-目的:在实例化一个子类,必须先实例其对应的父类,以确保子类可以正常调用基类对子类公开的变量和方法。另外,《Java编程思想》给了一个编写构造器的建议:用尽可能简单的方法使对象进入正常状态;如果可以的话,避免调用其它方法。

 

posted on 2019-07-10 09:31  我不吃番茄  阅读(165)  评论(0编辑  收藏  举报