Java程式設計師從笨鳥到菜鳥之(九十四)深入java虛擬機器(三)——類的生命週期 下)類的初始化
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
上接深入java虛擬機器——深入java虛擬機器(二)——類載入器詳解(上),在上一篇文章中,我們講解了類的生命週期的載入和連線,這一篇我們接著上面往下看。
類的初始化:在類的生命週期執行完載入和連線之後就開始了類的初始化。在類的初始化階段,java虛擬機器執行類的初始化語句,為類的靜態變數賦值,在程式中,類的初始化有兩種途徑:(1)在變數的宣告處賦值。(2)在靜態程式碼塊處賦值,比如下面的程式碼,a就是第一種初始化,b就是第二種初始化
public class Test{public static int a = 0;public static int b ;static{b=2;}}
靜態變數的宣告和靜態程式碼塊的初始化都可以看做靜態變數的初始化,類的靜態變數的初始化是有順序的。順序為類檔案從上到下進行初始化,想到這,想起來
package com.bzu.csh;class Singleton{private static Singleton singleton = new Singleton();public static int counter1;public static int counter2 = 0;private Singleton(){counter1++;counter2++;}public static Singleton getInstance(){return singleton;}}public class Test{public static void main(String[] args){Singleton singleton = Singleton.getInstance();System.out.println("counter1 = " + singleton.counter1);System.out.println("counter2 = " + singleton.counter2);}}
大家先看看這裡的程式會輸出什麼?
不知道大家的答案是什麼,如果不介意的話可以把你的答案寫到評論上,看看有多少人的答案和你一樣的。我先說說我剛開始的答案吧。我認為會輸出:
counter1 = 1
Counter2 = 1
不知道大家的答案是不是這個,反正我的是。下面我們來看一下正確答案:
不知道你做對沒有,反正我剛開始做錯了。好,現在我來解釋一下為什麼會是這個答案。在給出解釋之前,我們先來看一個概念:
Java程式對類的使用方式可分為兩種
主動使用
被動使用
•所有的Java虛擬機器實現必須在每個類或介面被Java程式“首次主動使用”時才初始化他們
主動使用(六種)
–建立類的例項
–訪問某個類或介面的靜態變數,或者對該靜態變數賦值
–呼叫類的靜態方法
–反射(如Class.forName(“com.bzu.csh.Test”))
–初始化一個類的子類
–Java虛擬機器啟動時被標明為啟動類的類(Java Test)
OK,我們開始解釋一下上面的答案,程式開始執行,首先執行main方法,執行main方法第一條語句,呼叫Singleton類的靜態方法,這裡呼叫Singleton類的靜態方法就是主動使用Singleton類。所以開始載入Singleton類。在載入Singleton類的過程中,首先對靜態變數賦值為預設值,
Singleton=null
counter1 = 0
Counter2 = 0
給他們賦值完預設值值之後,要進行的就是對靜態變數初始化,對宣告時已經賦值的變數進行初始化。我們上面提到過,初始化是從類檔案從上到下賦值的。所以首先給Singleton賦值,給它賦值,就要執行它的構造方法,然後執行counter1++;counter2++;所以這裡的counter1 = 1;counter2 = 1;執行完這個初始化之後,然後執行counter2的初始化,我們宣告的時候給他初始化為0 了,所以counter2 的值又變為了0.初始化完之後執行輸出。所以這是的
counter1 = 1
counter2 = 0
類初始化步驟
(1)假如一個類還沒有被載入或者連線,那就先載入和連線這個類
(2)假如類存在直接的父類,並且這個父類還沒有被初始化,那就先初始化直接的父類
(3)假如類中存在初始化語句,那就直接按順序執行這些初始化語句
在上邊我們我們說了java虛擬機器實現必須在每個類或介面被Java程式“首次主動使用”時才初始化他們,上面也舉出了六種主動使用的說明。除了上述六種情形,其他使用Java類的方式都被看作是被動使用,不會導致類的初始化。程式中對子類的“主動使用”會導致父類被初始化;但對父類的“主動”使用並不會導致子類初始化(不可能說生成一個Object類的物件就導致系統中所有的子類都會被初始化)
注:呼叫ClassLoader類的loadClass方法載入一個類,並不是對類的主動使用,不會導致類的初始化。
當java虛擬機器初始化一個類時,要求它的所有的父類都已經被初始化,但這條規則並不適用於介面。
在初始化一個類時,並不會先初始化它所實現的介面
在初始化一個介面時,並不會先初始化它的父介面
因此,一個父介面並不會因為它的子介面或者實現類的初始化而初始化。只有當程式首次使用特定介面的靜態變數時,才會導致該介面的初始化。只有當程式訪問的靜態變數或靜態方法確實在當前類或當前介面中定義時,才可以認為是對類或介面的主動使用 。如果是呼叫的子類的父類屬性,那麼子類不會被初始化。