java -- 变量初始化顺序

1. 引言

在一个的 java 程序中,为了保证程序的健壮性,在初始化一个对象之前, 应该保证对象中的变量都有进行初始化的操作。那么,在对象初始化过程中,变量加载的顺序大致是怎么样的呢?这篇文章主要探讨这个问题,包含普通变量静态变量静态代码块 的加载顺序。

2. 普通变量

在类中,变量定义位置的先后会影响到它们的加载顺序,但是,无论如何,它们都会在构造方法执行之前进行初始化,我们来看下面这段代码:

首先创建一个 Book 类,只定义一个有参的构造方法:

public class Book {
    public Book(int i){
        System.out.println("book" + i +" init ...");
    }
}

接着创建一个 BookStore 类,该类中有两个 Book 类的引用,并进行了初始化。注意,这边有意将 book2 写在 book1 上。

public class BookStore {
    public Book book2 = new Book(2);
    public Book book1 = new Book(1);

    public BookStore(){
        System.out.println("bookstore init ...");
    }
}

最后,在 main 创建一个 BookStore 对象:

public class MainApp {
    public static void main(String[] args){
        BookStore bookStore = new BookStore();
    }
}

最终运行结果如下,从结果可以看出,由于 book2 变量定义在 book1 之前,根据类加载普通变量的顺序,所以在加载时它在 book1 之前。

book2 init …

book1 init …

bookstore init …

3. 静态变量初始化

为了验证静态变量是在什么时候初始化的,我们在 BookStore 中添加一个 static 变量。

public class BookStore {
    public Book book2 = new Book(2);
    public Book book1 = new Book(1);

    public static Book book3 = new Book(3);

    public BookStore(){
        System.out.println("bookstore init ...");
    }
}

在 MainApp 中对 BookStore 进行两次初始化:

public class MainApp {
    public static void main(String[] args){
        BookStore bookStore = new BookStore();
        bookStore = new BookStore();
    }
}

运行结果如下,我们可以看出,static 变量在 book1、book2 这两个变量之前进行加载,说明 static 变量是一个类中最先进行初始化的。

之后,MainApp 中又进行了一次初始化,而此时 book3 并没有重新进行加载,说明静态变量只会在第一个 Book 创建时才会进行初始化,之后,静态变量不会再进行初始化操作了。

book3 init …
book2 init …
book1 init …
bookstore init …
book2 init …
book1 init …
bookstore init …

4. 静态代码块

java 中允许将多个静态初始化动作组织成一个特殊的 “静态语句”(有时也叫”静态块“),例如下面这个样子:

public class Test{
    int i;
    static{
        i = 4;
    }
}

静态代码块加载的顺序和静态变量加载规律一样,这里就不再进行重复说明。需要注意的是,当静态代码块碰到静态变量时会怎样呢?这就跟普通变量加载顺序是一致的,位置先后影响他们初始化的顺序,这个可以自行做实验进行验证。

5. 总结

通过上面几个简单的小实验,在这里总结一下对象的创建过程,这一部分主要是参考 《java 编程思想》第四版的内容。

我们在加载 Book 类时,

  1. 即使没有直接标明 static 关键字,构造器实际上也是静态方法。因此,当首次创建类型为 Book 的对象时,或者 Book 的静态变量 / 方法(包括构造方法)首次被访问时,Java 解释器必须查找类路径,以定位 Book.class 文件。
  2. 然后载入 Book.class,有关静态初始化的所有动作都会执行,因此,静态初始化只在 Class 对象首次被加载时进行一次。
  3. 当使用 new Book() 创建对象时,首先将在堆上为 Book 对象分配足够的空间
  4. 这块存储空间会被清零,所有基本数据类型设置为默认值(如 int、float 被设置为 0),引用类型被置为 null
  5. 执行所有出现于字段定义处的初始化动作
  6. 执行构造器。如果涉及继承时,这会牵涉到很多动作。

以上就是一个对象加载变量的顺序。

你可能感兴趣的:(java,基础,java核心基础)