父类与子类的初始化顺序

1. 构造器没有参数

创建爷爷类

public class GrandFather {
    public GrandFather() {
        System.out.println("爷爷");
    }
}

创建父亲类

public class Father extends GrandFather {
    public Father() {
        System.out.println("爸爸");
    }
}

创建A类

创建儿子类

public class A {
    public A() {
        System.out.println("A");
    }
}
public class Son extends Father {
    public Son() {
        System.out.println("儿子");
    }
     A a = new A();
    public static void main(String[] args) {
        new Son();
    }
}

运行结果:
爷爷
爸爸
A
儿子

结论:

  1. 构造过程是从父类“向外”扩散的,所以父类在子类构造器可以访问它之前,就已经完成了初始化,即使没有Son类的构造器,编译器也会默认合成一个构造器,然后调用父类的构造器。
  2. 虽然Son的构造方法在new A()之前,但是还是先执行了new A(),在执行Son的构造方法。也就是Son构造器初始化的时候会执行除构造函数和其他方法之外的其他代码;
接着在main方法中加入
getSuperClass(son.getClass());

getSuperClass方法体

    private static void getSuperClass(Class t) {
        System.out.println(t.getSuperclass());
        while (t!=null){
            getSuperClass(t.getSuperclass());
        }
    }

结果:
爷爷
爸爸
A
儿子
class javabianchengsixiang.Seven.Father
class javabianchengsixiang.Seven.GrandFather
class java.lang.Object
null(报异常)

结论:虽然没有显示的继承Object类,但是Son构造器会隐式的继承Object类

2. 构造器有参数

创建爷爷类

public class GrandFather {
    public GrandFather(int i) {
        System.out.println("爷爷");
    }
}
注意:创建父亲类

在这里插入图片描述
编译器提示我们不能这样创建;
解决办法有两种:

  1. 在爷爷类中显示的加入构造方法
  2. 使用super关键字,像这样:
    public class Father extends GrandFather {
        public Father() {
            super(666);
            System.out.println("爸爸");
        }
    }

儿子类

public class Son extends Father {
    public Son() {
        System.out.println("儿子");
    }
    public static void main(String[] args) {
        Son son = new Son();
    }
}

结果:
爷爷666
爸爸
儿子

结论:如果父类中的构造器有参数,则子类必须使用super关键字来继承。

3.初始化(包含继承)全过程

准备代码

public class Father {
    private int age = 50;
    protected int weight;
    public Father() {
        System.out.println("age="+age+",weight="+weight);
        weight=140;
    }
    private static int fa = printInit("static Facher fa initialized");
    static int printInit(String s){
        System.out.println(s);
        return 66;
    }
}


public class Son extends Father {
   private int so = printInit("Son so initialized");
   public Son() {
      System.out.println("so="+so);
      System.out.println("weight="+weight);
   }
   private static int son = printInit("static Son son initialized");
   public static void main(String[] args) {
      System.out.println("Son construct");
      new Son();
   }
}

结果:
static Facher fa initialized
static Son son initialized
Son construct
age=50,weight=0
Son so initialized
so=66
weight=140

过程:

  1. 鼠标右键点击Run Son.main()
  2. 类加载器开始加载Son类的编译代码(Son.class文件)。
  3. 在加载过程中通过extends发现有父类Father,于是Father.class被加载。(如果father有extends,则继续加载)
  4. 最终加载到Father.class,先执行static代码块 private static int fa = printInit("static Facher fa initialized");打印,并且把值66赋值给变量fa
  5. 父类static代码块执行完,会找它的子类的static代码块,也就是private static int son = printInit("static Son son initialized");打印,并且把值66赋值给变量son
  6. 到现在所有的static代码块都被初始化,然后执行main方法体代码,首先执行 System.out.println("Son construct");
  7. 接着执行new Son();
  8. 首先所有对象的所有基本类型和引用类型都设为默认值
  9. 接着加载父类Father的基本类型和引用类型(成员变量或者非静态字段),并且赋值; private int age = 50; protected int weight;
  10. 接着父类Father的构造器被调用。打印,并且140赋值给变量weight;
  11. 接着加载子类Son的基本类型和引用类型(成员变量或者非静态字段),并且赋值
  12. 接着执行Son的构造函数,打印

总结参考:https://www.cnblogs.com/xing901022/p/5507086.html
第一点,所有的类都会优先加载基类
第二点,静态成员的初始化优先
第三点,成员初始化后,才会执行构造方法
第四点,静态成员的初始化与静态块的执行,发生在类加载的时候。
第四点,类对象的创建以及静态块的访问,都会触发类的加载。

下面这段话引用自:
https://blog.csdn.net/u014745069/article/details/82655339
父类的静态字段——>父类静态代码块——>子类静态字段——>子类静态代码块——>
父类成员变量(非静态字段)——>父类非静态代码块——>父类构造器——>子类成员变量——>子类非静态代码块——>子类构造器

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值