java 类加载顺序——java中类的静态代码块、构造代码块、构造方法、静态成员的初始化顺序详解

一、描述

java中类的静态代码块、构造代码块、构造方法、静态成员的初始化顺序:

  首先,在类加载时,为类中的静态成员变量分配内存空间,并为其赋予默认值(整数型为0,浮点型为0.0,布尔型为false,字符型为'\u0000',引用型为null);

  其次,执行静态成员变量的显式初始化操作。静态成员的初始化方法有两种,其一为在声明的时候直接初始化,其二为使用静态代码块进行初始化,

 这两种初始化方式会按照在类中的出现顺序来执行,而且只在类加载的时候执行一次。

  再次,如果创建了类的对象,便会在堆中为类的实例分配内存空间,实例变量也会被初始化为默认值(默认值与静态成员的默认值xiangtong)。

  再次,执行实例变量的显式初始化操作,其中包含两种初始化操作,其一为声明时直接初始化,其二为在构造代码块中进行初始化,这两种初始化方法也按照出现的先后次序来依次执行。 

最后,执行类的构造方法,构造方法是每创建一个对象就调用一次,可以进行多次调用。

 总结:在类加载时,先按照静态成员变量或者静态代码块的出现次序来初始化静态成员(类加载时只执行一次);

 然后按照普通成员变量和构造代码块的出现顺序来初始化普通成员变量(创建几个对象执行几次);

 最后调用类的构造方法,对成员变量进行初始化(创建几个对象执行几次)。

 执行优先次序:静态成员和静态代码块 > 成员变量和构造代码块 > 构造方法

二、源代码

package tong.yue.day4_25;
/**
 * java中类的静态代码块、构造代码块、构造方法、静态成员的初始化顺序:
 * 首先,在类加载时,为类中的静态成员变量分配内存空间,并为其赋予默认值(整数型为0,浮点型为0.0,布尔型为false,字符型为'\u0000',引用型为null);
 * 其次,执行静态成员变量的显式初始化操作。静态成员的初始化方法有两种,其一为在声明的时候直接初始化,其二为使用静态代码块进行初始化,
 * 这两种初始化方式会按照在类中的出现顺序来执行,而且只在类加载的时候执行一次。
 * 再次,如果创建了类的对象,便会在堆中为类的实例分配内存空间,实例变量也会被初始化为默认值(默认值与静态成员的默认值xiangtong)。
 * 再次,执行实例变量的显式初始化操作,其中包含两种初始化操作,其一为声明时直接初始化,其二为在构造代码块中进行初始化,这两种初始化方法也按照出现的先后次序来依次执行。
 * 最后,执行类的构造方法,构造方法是每创建一个对象就调用一次,可以进行多次调用。
 * 
 * 总结:在类加载时,先按照静态成员变量或者静态代码块的出现次序来初始化静态成员(类加载时只执行一次);
 * 然后按照普通成员变量和构造代码块的出现顺序来初始化普通成员变量(创建几个对象执行几次);
 * 最后调用类的构造方法,对成员变量进行初始化(创建几个对象执行几次)。
 * 执行优先次序:静态成员和静态代码块 > 成员变量和构造代码块 > 构造方法
 * 
 * @author tong
 *
 */
public class Car {
    // 有参构造器1
    public Car(String color) {
        System.out.println("执行构造器Car(String)");
        this.color = color;
    }
 
    // 构造代码块1
    {
        System.out.println("执行初始化块1");
    }
    // 静态初始化块1
    static {
        System.out.println("执行静态初始化块1");
        length = 3.2;
    }
 
    // 实例变量直接初始化
    private String color = getColor();
    // 静态成员变量直接初始化
    private static double length = getLength();
 
    // // 构造代码块2
    {
        System.out.println("执行初始化块2");
    }
    
    // 静态初始化块2
    static {
        System.out.println("执行静态初始化块2");
        length = 3.2;
    }
    //静态成员变量初始化
    private static double width = getWidth();
    //普通成员变量初始化
    private int maxSpeed = getMaxSpeed();
    //无参构造器2
    public Car() {
        System.out.println("执行构造器Car()");
        color = "red";
    }
    //普通成员方法,获取maxSpeed
    private int getMaxSpeed() {
        System.out.println("初始化成员变量speed");
        return 180;
    }
    //静态成员方法,获取width
    private static double getWidth() {
        System.out.println("初始化静态成员变量width");
        return 2.0;
    }
    //静态成员方法,获取length
    private static double getLength() {
        System.out.println("初始化静态成员变量length");
        return 3.2;
    }
    //普通成员方法,获取color
    private String getColor() {
        System.out.println("初始化实例变量color");
        return color;
    }
 
    public static void main(String[] args) {
        new Car();  //调用无参构造方法创建对象
        new Car("red");   //调用有参构造方法创建对象
 
    }
}

执行结果:


三、总结

1、静态成员和静态代码块两个同类出现的顺序决定了初始化顺序,它们的执行一定先于普通成员变量初始化、构造代码块初始化和构造函数;

2、普通成员和普通构造代码块两者在代码中的出现顺序决定了初始化顺序,它们的执行一定后于静态成员和静态代码块,但是先于构造方法;

3、与上面两者相比,构造函数永远是最后执行的。

你可能感兴趣的:(java基础坑点,java)