详解Java的静态代码块、非静态代码块、静态方法、构造方法、构造代码块

有过java基础的同学肯定绕不开这个小山坡,静态代码块、非静态代码块、静态方法、构造方法、构造代码块,这些,哪些先执行,哪些后执行,为什么呢?

首先,先说下论点,再用code佐证,最后探讨机制。

java类加载顺序

1、虚拟机在首次加载Java类时,会对静态初始化块、静态成员变量、静态方法进行一次初始化 2、只有在调用new方法时才会创建类的实例 3、类实例创建过程:按照父子继承关系进行初始化,首先执行父类的初始化块部分,然后是父类的构造方法;再执行本类继承的子类的初始化块,最后是子类的构造方法 4、类实例销毁时候,首先销毁子类部分,再销毁父类部分

非静态代码块是在每次实例化对象时被调用的。new对象之后发生的事情:给对象的实例变量(非“常量”)分配内存空间,默认初始化成员变量;成员变量声明时的初始化;初始化块初始化(又称为构造代码块或非静态代码块);构造方法初始化。

示例代码

public class Test01 {
    public static void main(String[] args) {
        B b = new B();
    }
}
class B extends A{
    static{
        System.out.println("子类的静态代码块");
    }
    C c = new C();
    {
        System.out.println("子类的构造代码块");
        C.method();
    }
    B(){
        System.out.println("子类的构造方法");
    }
}
class A{
    static{
        System.out.println("父类的静态代码块");
    }
    C c = new C();
    A(){
        System.out.println("父类的构造方法");
    }
}
class C{
    static public  void method(){
        System.out.println("C的静态方法");
    }
    static{
        System.out.println("C类的静态代码块");
    }
    C(){
        System.out.println("C的构造方法");
    }
}

代码运行的结果:

父类的静态代码块
子类的静态代码块
C类的静态代码块
C的构造方法
父类的构造方法
C的构造方法
子类的构造代码块
C的静态方法
子类的构造方法

解读:
首次加载Java类时,会对静态初始化块、静态成员变量、静态方法进行一次初始化,而B继承A,本来要先执行B的静态代码块,但按照父子关系初始化,A加了个塞,先执行A的静态代码块,打印“父类的静态代码块”;B的静态代码块也加载,打印“子类的静态代码块”;在父类中把C类也加载进来了,静态代码块执行,打印“C类的静态代码块”,C在new的时候,构造方法执行,打印“C的构造方法”;然后执行到A的构造方法,打印“父类的构造方法”;接着在B类继续向下执行,又new了个C,打印“C的构造方法”,然后向下执行非静态代码块,打印“子类的构造代码块”以及“C的静态方法”;最后B类的构造方法执行,打印“子类的构造方法”。

机制

具体内存中如何加载,暂时还没时间看,TODO,等看到java的类加载机制再详细探讨。

根据反编译的结果来看,整个运行过程是这样的:

public class Test01 {
    public static void main(String[] args) {
        B b = new B();
    }
}
class B extends A{
    static{
        System.out.println("子类的静态");
    }
    C c ;

    B(){
        super();
        c = new C();
        System.out.println("子类的构造代码块");
        C.method();
        System.out.println("子类的构造方法");
    }
    public void method(){
        System.out.println("子类的成员方法");
    }
}
class C{
    static public  void method(){
        System.out.println("C的静态方法");
    }
    static{
        System.out.println("C类的静态");
    }
    C(){
        super();

        System.out.println("C的构造方法");
    }
}
class A{
    static{
        System.out.println("父类的静态");
    }
    C c ;
    A(){
        super();
        c = new C();
        System.out.println("父类的构造方法");
    }
}

构造方法里面,先super(),再成员变量(c=new C()),再其他代码,操作完毕,依次读取。这就是内存中真实的运行规则。

扩展

看下面的题,请问输出的是什么

public class Test03 {
    public static void main(String[] args) {
        Zi zi = new Zi();
    }
}
class Zi extends Fu{
    public int count=3;
    public Zi(){
    }
    public void print(){
        System.out.println("Zi..."+count);
    }
}
class Fu{
    public int count=10;
    public Fu(){
        print();
    }
    public void print(){
        System.out.println("Fu..."+count);
    }
}

同之前的逻辑,改造后代码如下:

扫描二维码关注公众号,回复: 6395574 查看本文章
public class Test03 {
    public static void main(String[] args) {
        Zi zi = new Zi();
    }
}
class Zi extends Fu{
    public int count=0;//默认初始值为0
    public Zi(){
        super();
        count=3;
    }
    public void print(){
        System.out.println("Zi..."+count);
    }
}
class Fu{
    public int count=0;
    public Fu(){
        super();
        count=10;
        print();
    }
    public void print(){
        System.out.println("Fu..."+count);
    }
}

Zi zi = new Zi(),过去找子类的构造方法,super(),此时子类的count还是0,找父类的构造方法,父类,的count改为10,print(),子类自己有重写,找子类自己的,count也是找子类自己的,此时还是0,结果Zi...0

猜你喜欢

转载自blog.csdn.net/wjl31802/article/details/90199020
今日推荐