2012-08-13 71 views
2

我在網上發現了這個代碼,其中人正在實例化一個在類外部具有私有構造函數的類。我無法理解這是如何工作的,因爲我之前讀過的內容是,在類中使用私有構造函數,因此無法在類之外實例化。在類外部實例化私有構造的類

public final class A extends B { 
    private A(Something, Something) 
    { 
    //Something 
    } 

    public void someMethods() 
    { 
    //Something 
    } 
} 

public final class B { 
    private A a; 
    public void someMethod() 
    { 
    final ObjectInputStream objectInputStream = new ObjectInputStream(
          new ByteArrayInputStream(buffer.toByteArray())); 
    a = (A) objectInputStream.readObject(); 
    objectInputStream.close(); 

    a.someMethods(); 
    } 
} 

我只是想了解這裏究竟發生了什麼?我試着在ObjectInputStream上閱讀,但沒有得到任何東西。

回答

2

那麼,構造函數永遠不會被調用,因爲對象沒有被構造,而是反序列化。因此訪問修飾符在這裏沒有效果。

序列化基本上是將堆的部分內容寫入某個流/文件等的過程。構造一個對象將在堆上創建一個新對象並調用構造函數來初始化它。然後它具有在序列化期間保留的狀態。因此,在反序列化時不需要再次初始化該對象。這就像將流/文件堆中的那部分再次讀入內存一樣。

除此之外,請記住,有方法通過使用反射來繞過訪問修飾符。

+0

那麼這是否意味着這個特定對象的行爲就像一個靜態對象?意思是說,它只有一個實例,因爲它已經從堆中映射出來了?不知道我是否清楚。 – noMAD 2012-08-13 17:21:46

+1

好吧,總是隻有一個對象的實例,因爲一個對象_is_是一個類的實例。如果你的意思是,如果這是一個單例(只有一個類的一個實例),那麼答案是否定的。您可以序列化和反序列化同一個類的多個對象。 – Thomas 2012-08-15 08:01:43

1

這與序列化有關,而當您反序列化時,實際上不會調用構造函數。

5

看起來像代碼通過序列化實例化一個對象,然後將該對象轉換爲類A.這裏沒有任何地方是調用的A類構造函數。

+0

+1您不需要訪問構造函數來執行反序列化。 – 2012-08-13 16:48:58

+2

在OpenJDK中,它調用'Unsafe.allocateInstance(Class)',它在不調用構造函數的情況下分配一個類的實例。它需要做到這一點,以恢復字段,因爲它序列化他們和構造函數可以有副作用。 – 2012-08-13 16:53:22

+0

作爲參考,OP,這個_appears_是一種骯髒的黑客攻擊。 – 2012-08-13 16:56:23

相關問題