2011-08-31 535 views
-1

每次創建包含這些變量的對象的新實例時,都會初始化靜態變量嗎?或者當對象首次被調用時,它們是否只初始化一次?靜態變量初始化

+7

你是什麼意思的「實例靜態變量」?這就像談論「String int變量」。 –

+2

有沒有這樣的事情作爲實例靜態變量。你有一個實例變量或靜態(類)變量! –

+3

而且你不會調用一個對象 - 只有它的方法。 – DJClayworth

回答

11

你說

被初始化例如靜態變量...

停在那兒,聲明是沒有意義的。靜態變量存在於類中,而不是在任何特定的實例上。它們在初始化過程中初始化,該過程在創建實例,運行類的靜態方法或訪問類的靜態變量時運行。 (完全披露,@布魯諾的回答讓我知道這些信息)。

+1

類加載!=類初始化。 –

+1

@bruno「編譯器實際上做的是在內部產生一個類初始化例程,它按照它們出現在類聲明中的順序將所有靜態變量初始化器和所有靜態初始化器代碼塊組合在一起。只會在班級第一次加載時自動運行,一次。「從簡單的Java – hvgotcodes

+1

hvgotcodes,不要相信書籍。 **這簡直是錯誤的**。去檢查虛擬機規格部分2.17.4和2.17.5(在我的答案下面的鏈接)。一個類在加載時不會被初始化。如果您使用多個類加載器,則可以多次加載一個類並進行多次初始化。 –

3

靜態字段的類(的初始化期間初始化不混合初始化裝載,他們是不同的東西 - 一個類可以加載,你可以做反射就可以了,沒有永遠不會初始化它)。

此外,如果您使用多個ClassLoader s,類初始化可能會多次發生給定的類。

見VM規格section 2.17.4, Initializationsection 2.17.5, Detailed initialization procedure關於更多的細節時,完全是一個類被加載,什麼時候它會被初始化..

編輯:簡單的例子,將顯示一個類如何被裝載初始化多次,並且裝載並不自動意味着初始化:

public class A { static { System.out.println("I've been initialized!"); } } 
public class Main { 
    public static void main(String... args) { 
    ClassLoader cl = new URLClassLoader(..., null); 
    System.out.println("loading..."); 
    Class<?> aClass = cl.loadClass("A"); 
    // here you could perform reflection on aClass, without initializing it 
    System.out.println("Will be initialized now:"); 
    Object o = aClass.newInstance(); 
    System.out.println("Let's load once again..."); 
    ClassLoader cl2 = new URLClassLoader(..., null); 
    Class<?> aClass2 = cl2.loadClass("A"); 
    System.out.println("Will be initialized a second time:"); 
    Object o2 = aClass2.newInstance(); 

    // the following is false: 
    System.out.println("aClass1.equals(aClass2) = " + aClass1.equals(aClass2)); 

    // the following is true: 
    System.out.println("aClass1.getName().equals(aClass2.getName())" + aClass1.getName().equals(aClass2.getName())); 
    } 
} 

(我希望當您指定的URLClass缺少URL[]對象這個編譯裝載機的構造......)

注意,有必要設定的類加載器的父母null,否則他們的父母將是主要的應用程序類加載器(即加載的類Main),則因爲Java代表相同首先默認加載到父類加載器,如果類A在類路徑中,則只會看到加載和初始化一次。

最後,請注意,Class.load("A")不等於classLoader.loadClass("A")。如果您檢查文檔Class.load(String),您會看到此方法加載初始化該類。有一個Class.load(...)超載,它需要一個布爾值來指示它是否應該初始化類。

+0

可以一個類多次初始化?第2.17.5節中的一行表示「如果類或接口已經被初始化,則不需要進一步的操作。釋放對象的鎖並正常完成。」 – hvgotcodes

+1

是的。在運行時,一個類由元組(ClassLoader,Package,Name)標識。如果你使用2個不相關的類加載器,你將有2 *個不同的*類(具有相同的名稱,以便它們各自的Class對象是!c1.equals(c2),但是c1.getName()。equals(c2)。 getName())是true),所以初始化過程可以每個發生一次。 –