類在何時加載和初始化

本文由 ImportNew - 劉志軍 翻譯自 Javarevisited。歡迎加入翻譯小組。轉載請見文末要求。html

理解類在JVM中何時被加載和初始化是Java編程語言中的基礎概念,正由於有了Java語言規範,咱們才能夠清晰的記錄和解釋這個問題,可是不少Java程序員仍然不知道何時類被加載,何時類被初始化,類加載和初始化好像讓人很困惑,對初學者難以理解,在這篇教程中咱們將看看類加載何時發生,類和接口是如何被初始化的,我並不會拘泥於類加載器的細節或者說類加載器的工做方式。僅僅使這篇文章更加專一和簡結。java

類何時加載程序員

類的加載是經過類加載器(Classloader)完成的,它既能夠是餓漢式[eagerly load](只要有其它類引用了它就加載)加載類,也能夠是懶加載[lazy load](等到類初始化發生的時候才加載)。不過我相信這跟不一樣的JVM實現有關,然而他又是受JLS保證的(當有靜態初始化需求的時候才被加載)。面試

類何時初始化

加載完類後,類的初始化就會發生,意味着它會初始化全部類靜態成員,如下狀況一個類被初始化:編程

  1. 實例經過使用new()關鍵字建立或者使用class.forName()反射,但它有可能致使ClassNotFoundException。
  2. 類的靜態方法被調用
  3. 類的靜態域被賦值
  4. 靜態域被訪問,並且它不是常量
  5. 在頂層類中執行assert語句

反射一樣可使類初始化,好比java.lang.reflect包下面的某些方法,JLS嚴格的說明:一個類不會被任何除以上以外的緣由初始化。編程語言

類是如何被初始化的

如今咱們知道何時觸發類的初始化了,他精確地寫在Java語言規範中。但瞭解清楚 域(fields,靜態的仍是非靜態的)、塊(block靜態的仍是非靜態的)、不一樣類(子類和超類)和不一樣的接口(子接口,實現類和超接口)的初始化順序也很重要類。事實上不少核心Java面試題和SCJP問題都是基於這些概念,下面是類初始化的一些規則:this

  1. 類從頂至底的順序初始化,因此聲明在頂部的字段的早於底部的字段初始化
  2. 超類早於子類和衍生類的初始化
  3. 若是類的初始化是因爲訪問靜態域而觸發,那麼只有聲明靜態域的類才被初始化,而不會觸發超類的初始化或者子類的初始化即便靜態域被子類或子接口或者它的實現類所引用。
  4. 接口初始化不會致使父接口的初始化。
  5. 靜態域的初始化是在類的靜態初始化期間,非靜態域的初始化時在類的實例建立期間。這意味這靜態域初始化在非靜態域以前。
  6. 非靜態域經過構造器初始化,子類在作任何初始化以前構造器會隱含地調用父類的構造器,他保證了非靜態或實例變量(父類)初始化早於子類

初始化例子spa

這是一個有關類被初始化的例子,你能夠看到哪一個類被初始化翻譯

1code

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

/**

 * Java program to demonstrate class loading and initialization in Java.

 */

public class ClassInitializationTest {

 

    public static void main(String args[]) throws InterruptedException {

 

        NotUsed o = null; //this class is not used, should not be initialized

        Child t = new Child(); //initializing sub class, should trigger super class initialization

        System.out.println((Object)o == (Object)t);

    }

}

 

/**

 * Super class to demonstrate that Super class is loaded and initialized before Subclass.

 */

class Parent {

    static { System.out.println("static block of Super class is initialized"); }

    {System.out.println("non static blocks in super class is initialized");}

}

 

/**

 * Java class which is not used in this program, consequently not loaded by JVM

 */

class NotUsed {

    static { System.out.println("NotUsed Class is initialized "); }

}

 

/**

 * Sub class of Parent, demonstrate when exactly sub class loading and initialization occurs.

 */

class Child extends Parent {

    static { System.out.println("static block of Sub class is initialized in Java "); }

    {System.out.println("non static blocks in sub class is initialized");}

}

 

Output:

static block of Super class is initialized

static block of Sub class is initialized in Java

non static blocks in super class is initialized

non static blocks in sub class is initialized

false

從上面結果能夠看出:

  1. 超類初始化早於子類
  2. 靜態變量或代碼塊初始化早於非靜態塊和域
  3. 沒使用的類根本不會被初始化,由於他沒有被使用

再來看一個例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

/**

 * Another Java program example to demonstrate class initialization and loading in Java.

 */

 

public class ClassInitializationTest {

 

    public static void main(String args[]) throws InterruptedException {

 

       //accessing static field of Parent through child, should only initialize Parent

       System.out.println(Child.familyName);

    }

}

 

class Parent {

    //compile time constant, accessing this will not trigger class initialization

    //protected static final String familyName = "Lawson";

 

    protected static String familyName = "Lawson";

 

    static { System.out.println("static block of Super class is initialized"); }

    {System.out.println("non static blocks in super class is initialized");}

}

 

Output:

static block of Super class is initialized

Lawson

分析:

  1. 這裏的初始化發生是由於有靜態域被訪問,並且不一個編譯時常量。若是聲明的」familyName」是使用final關鍵字修飾的編譯時常量使用(就是上面的註釋代碼塊部分)超類的初始化就不會發生。
  2. 儘管靜態與被子類所引用可是也僅僅是超類被初始化

還有另一個例子與接口相關的,JLS清晰地解釋子接口的初始化不會觸發父接口的初始化。強烈推薦閱讀JLS14.4理解類加載和初始化細節。以上全部就是有關類被初始化和加載的所有內容。

原文連接: Javarevisited 翻譯: ImportNew.com - 劉志軍
譯文連接: http://www.importnew.com/6579.html
[ 轉載請保留原文出處、譯者和譯文連接。]

相關文章
相關標籤/搜索