java基础,静态变量,静态初始化块,初始化快,成员变量的初始化顺序

java基础,静态变量,静态初始化块,初始化快,成员变量的初始化顺序

从这篇文章java基础-反射1(类型信息,Class对象简介,Class对象初始化)
我们可以了解到类在第一次使用时类加载到内存中的顺序有三个步骤

  1. 类的加载:由类加载器执行,根据类名查找.class文件,并从中创建一个class对象
  2. 类的链接:验证.class文件(字节码文件)看其结构是否完整,并且为静态域分配空间
  3. 类的初始化:如果类有父类则初始化父类,执行父类的静态初始化块,和静态初始化器,然后执行自己的。

我们从这里可以解决一个笔试题(面试题)就是JAVA变量的初始化顺序。总体可以概括为:

  1. (静态变量,静态初始化块)> [(成员变量,初始化块)>构造器]
  2. (静态变量,静态初始化块)中的先后顺序由静态变量,和静态初始化块在代码中出现的顺序决定
  3. (成员变量,初始化块)中的先后顺序由成员变量,和初始化块在代码中出现的顺序决定

因为静态成员是属于类的,在一加载类的时候就要进行初始化,而成员变量,初始化块是属于对象的,只有在创建对象时才会进行初始化。

下面我们就来举一个例子:
我们首先创建三个类
祖父类:

/**
 * Created by IntelliJ IDEA.
 * User:hubin
 * Description:祖父类
 * Date:2017/11/30
 * Time:15:46
 */
public class Grandfather {
    private static int age;
    private int  weight;

    static {
        System.out.println("进行 Grandfather 的静态初始化块");
        System.out.println("Grandfather 自动初始化的静态变量 age =" + age);
    }


    {
        System.out.println("进行 Grandfather 的初始化块");
        System.out.println("Grandfather 自动初始化的成员变量 weight =" + weight);

    }

    public Grandfather(){
        System.out.println("进行 Grandfather 的构造器");
        age = 100;
        weight = 200;
        System.out.println("Grandfather 手动初始化的静态变量 age =" + age);
        System.out.println("Grandfather 手动初始化的成员变量 weight =" + weight);
        System.out.println();  System.out.println();


    }
}

父亲类:

/**
 * Created by IntelliJ IDEA.
 * User:hubin
 * Description:父亲类
 * Date:2017/11/30
 * Time:15:52
 */
public class Father  extends  Grandfather{
    private static int age;
    private int  weight;
    static {
        System.out.println("进行 Father 的静态初始化块");
        System.out.println("Father 自动初始化的静态变量 age =" + age);
    }


    {
        System.out.println("进行 Father 的初始化块");
        System.out.println("Father 自动初始化的成员变量 weight =" + weight);

    }
    public Father(){
        System.out.println("进行 Father 的构造器");
        age = 50;
        weight = 100;
        System.out.println("Father 手动初始化的静态变量 age =" + age);
        System.out.println("Father 手动初始化的成员变量 weight =" + weight);
        System.out.println();  System.out.println();


    }
}

儿子类:

/**
 * Created by IntelliJ IDEA.
 * User:hubin
 * Description:儿子类
 * Date:2017/11/30
 * Time:15:53
 */
public class Son extends Father{
    private static int age;
    private int  weight;
    static {
        System.out.println("进行 Son 的静态初始化块");
        System.out.println("Son 自动初始化的静态变量 age =" + age);
        System.out.println();
        System.out.println();
    }

    {
        System.out.println("进行 Son 的初始化块");
        System.out.println("Son 自动初始化的成员变量 weight =" + weight);


    }

    public Son(){
        System.out.println("进行 Son 的构造器");
        age = 25;
        weight = 50;
        System.out.println("Son 手动初始化的静态变量 age =" + age);
        System.out.println("Son 手动初始化的成员变量 weight =" + weight);
        System.out.println();  System.out.println();

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

    }
}

运行结果如下:
这里写图片描述

我们看到,儿子类继承至父亲类,父亲类继承至祖父类,每个类中都有一个静态变量age和成员变量weight,我们在定义变量时都没有给他们赋值。然后每个类都有一个静态初始化块,和初始化块,静态初始化块中打印了静态初始化变量age的值(在这之前我们并没有给它赋值),在初始化块中我们打印了成员变量weight的值(在这之前我们没有给它赋值)。
然后在每个的构造方法中给各自的age和weight赋值,然后打印出来。
首相我们来看打印的第一部分:
这里写图片描述

从上面打印出来的信息可以看出:

  1. 首先进行的是GrandFather的静态初始化块
  2. 然后是Father的静态初始化块
  3. 最后是age的静态初始化块

所以类的初始化最先初始化是对静态成员,并且如果类有父类则先初始化父类,然后才是初始化自己.

从类加载到JVM中的步骤的第三部也可以看出,先初始化父类的静态成员,然后再是初始化自己的。如下:

  1. 类的初始化:如果类有父类则初始化父类,执行父类的静态初始化块,和静态初始化器,然后执行自己的。

那么同一类中的静态初始化块,和静态初始化成员谁先执行喃?
从上面可以看出,在执行静态初始化块前我们并没有对age初始化,但是却打印出来0,那是因为系统自动帮我们初始化了0。

然后我们来看第二部分

这里写图片描述

当静态变量初始化完成后(类已经加载完成)后,创建对象时就要初始化成员变量了,从上面可以看出。

  1. 首先进行的是GrandFather的初始块,然后是GrandFather的构造器
  2. 再次进行Father的初始块,然后是Father的构造器
  3. 最后进行Son的初始块,然后是Son的构造器

从上面可以看出,在创建对象时(假定这个时候类已经被加载到内存中了,这样就不会初始化静态成员)首先会初始化父类的成员变量,然后再是自己的。

综上,我们可以看出变量的初始化顺序是

(静态初始化块,静态变量) >[(初始化块,成员变量)>构造器]

猜你喜欢

转载自blog.csdn.net/hubin916/article/details/78676930