Initialization and Class loading

  可以说,类的代码在初次使用时才加载。这通常指加载发生于创建类的第一个对象之时,但当访问

static域或static方法时,也会发生加载(通过下面的这段代码验证)。

class LoadTest {
    // The static clause is executed upon class loading:
    static {
        System.out.println("Loading LoadTest");
    }
    static void staticMember() {}
    static int i = 0;
}
public class classLoading {
    public static void main(String args[]) {
        System.out.println("Calling static member");
        //new LoadTest();    // 1
        //LoadTest.staticMember();    // 2
        LoadTest.i++;    // 3
        System.out.println("Creating an object");
    }
}

  Output:

lxw@22:39:26:~/eclipse/java/javaComLine$ java classLoading 
Calling static member
Loading LoadTest
Creating an object

  无论保留语句1,语句2还是语句3,代码运行结果都是上面的结果。

  所有的static对象和static代码段会在加载时按照程序中的顺序(定义类时的书写顺序)而依次初始化。

  本文将以下面的代码为例展开论述: 

class Insect {
  private int i = 9;
  protected int j;
  Insect() {
    System.out.println("i = " + i + ", j = " + j);
    j = 39;
  }
  private static int x1 =
    printInit("static Insect.x1 initialized");
  static int printInit(String s) {
    System.out.println(s);
    return 47;
  }
}

public class Beetle extends Insect {
  private int k = printInit("Beetle.k initialized");
  public Beetle() {
    System.out.println("k = " + k);
    System.out.println("j = " + j);
  }
  private static int x2 =
    printInit("static Beetle.x2 initialized");
  public static void main(String[] args) {
    System.out.println("Beetle constructor");
    //Beetle b = new Beetle();    // 1 
    //Beetle b;    //2
  }
}

Output:

lxw@11:03:16:~/eclipse/java/javaComLine$ java Beetle 
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor

Analyze:

  Part 1.

  上面的代码执行时,首先将试图访问main(),于是开始启动并找出Beetle类的编译代码,在加载的过程中

编译器注意到它有一个基类,于是先对基类进行加载。此时基类中的static初始化开始被执行,然后执行导出

类中的static初始化。”先执行基类然后再执行导出类“的原因是导出类的static初始化可能会依赖于基类成员是

否被初始化。

  简略的说就是:基类的static数据成员初始化 -> 导出类的static数据成员初始化 -> main()

  至此,不管代码中是否创建一个基类或导出类的对象都执行这些步骤。 

  Part 2.

  更改上面的代码,将语句2的注释去掉,则运行结果与上面的结果相同。

  Part3.

  更改上面的代码,将语句1的注释去掉:

  Output:  

lxw@22:55:00:~/eclipse/java/javaComLine$ java Beetle 
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
i = 9, j = 0
Beetle.k initialized
k = 47
j = 39

  请注意各个输出的顺序。当用new创建导出类的一个对象时,其执行顺序如下:

  1. 基类初始化:先是基类的非静态成员初始化,然后是基类构造器的执行

  2. 导出类初始化:先是导出类的非静态成员初始化,然后是导出类构造器的执行

原文地址:https://www.cnblogs.com/lxw0109/p/Initialization_and_class_loading.html