全面了解JAVA类的初始化顺序 static修饰,静态代码块,继承等

面试中我们常常会问到关于类初始化的问题,那么关于一个类的初始化到底是按照怎么的顺序进行的呢
假如一个Son 类继承了 Parent 类 当我们实例化Son的时候是先执行父类还是先执行子类呢?
可能有的开发会说当然是先执行父类了 没错 就是先从父类开始执行的
那么当我们执行父类的时候 当父类和子类都有 静态成员变量 有普通的成员变量时 静态代码块 构造器 时
他们之间的执行顺序到底是怎么样的呢?
废话不多说请看代码

public class DeBugPrint {
    public DeBugPrint(String msg) {
        System.out.println(msg);
    }
}
public class Parent {
    DeBugPrint deBugPrint1 = new DeBugPrint("Parent的普通成员变量初始化了");
    static DeBugPrint deBugPrint2 = new DeBugPrint("Parent的静态成员变量初始化了");
    Parent(){
        deBugPrint2 = new DeBugPrint("执行了构造方法 对 Parent的静态成员变量进行赋值");
        deBugPrint1 = new DeBugPrint("执行了构造方法 对 Parent的普通成员变量进行赋值");
    }
    static {
        deBugPrint2 = new DeBugPrint("执行了静态代码块 对 Parent的静态成员变量进行赋值");
    }
}
public class Son extends Parent{
    DeBugPrint deBugPrint1 = new DeBugPrint("Son的普通成员变量初始化了");
    static DeBugPrint deBugPrint2 = new DeBugPrint("Son的静态成员变量初始化了");

    Son(){
        deBugPrint2 = new DeBugPrint("执行了构造方法 对 Son的静态成员变量进行赋值");
        deBugPrint1 = new DeBugPrint("执行了构造方法 对 Son的普通成员变量进行赋值");
    }
    static {
        deBugPrint2 = new DeBugPrint("执行了静态代码块 对 Son的静态成员变量进行赋值");
    }


    public static void funStatic() {
        System.out.println("执行了static修饰的funStatic方法");
    }
}
public class test1 {
    public static void main(String[] args) {
        Son.funStatic();
    }
}

test1的执行结果如下:

Parent的静态成员变量初始化了
执行了静态代码块 对 Parent的静态成员变量进行赋值
Son的静态成员变量初始化了
执行了静态代码块 对 Son的静态成员变量进行赋值
执行了static修饰的funStatic方法

从这个结果中我们可以看出 当直接调用静态方法时 只对父类及其子类的静态资源(静态变量及静态代码块)进行初始化

public class test2 {
    public static void main(String[] args) {
        Son son = new Son();
    }
}

test2的执行结果如下:

Parent的静态成员变量初始化了
执行了静态代码块 对 Parent的静态成员变量进行赋值
Son的静态成员变量初始化了
执行了静态代码块 对 Son的静态成员变量进行赋值
Parent的普通成员变量初始化了
执行了构造方法 对 Parent的静态成员变量进行赋值
执行了构造方法 对 Parent的普通成员变量进行赋值
Son的普通成员变量初始化了
执行了构造方法 对 Son的静态成员变量进行赋值
执行了构造方法 对 Son的普通成员变量进行赋值

当我们对Son进行实例化时,这其实也是一个类完整的初始化过程,也是我们主题要研究的内容对于继承关系,对于静态变量,对于静态代码块他们之间的实例化顺序,看到这个结果我们可能会带着些许的疑惑,不过仔细研究也会发现这样其实也是合情合理

public class test3 {
    public static void main(String[] args) {
       Son.funStatic();
        System.out.println("+++++++++++++++++++++++++++++++++++++++++++");
        Son son1 = new Son();
    }
}

test3的执行结果如下:

Parent的静态成员变量初始化了
执行了静态代码块 对 Parent的静态成员变量进行赋值
Son的静态成员变量初始化了
执行了静态代码块 对 Son的静态成员变量进行赋值
执行了static修饰的funStatic方法
+++++++++++++++++++++++++++++++++++++++++++
Parent的普通成员变量初始化了
执行了构造方法 对 Parent的静态成员变量进行赋值
执行了构造方法 对 Parent的普通成员变量进行赋值
Son的普通成员变量初始化了
执行了构造方法 对 Son的静态成员变量进行赋值
执行了构造方法 对 Son的普通成员变量进行赋值

这个结果你有没有感到意外呢,静态资源只被调用funStatic()静态方法时被初始化了一次,当对Son进行实例化时则静态资源没有被重新初始化,这也跟static关键字的特性有关,有兴趣的同学可以深入研究.

总结:
有父类 优先初始化父类
有static修饰 优先执行所有static
先初始化普通成员变量 再 执行构造器

第一次写博客,肯定有不足的地方,若有错误之处请及时指出以免误导他人.如果问题可在评论去提出共同探讨相互学习.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值