2014-01-26 90 views
6

我要通過有效的Java單身,和整個這個例子來。反序列化在Java

class Elvis implements Serializable { 
    public static final Elvis inst = new Elvis(); 
    private Elvis() { 
     System.out.println("In elvis constructor "); 
    } 

    public static Elvis getInstance() { 
     return inst; 
    } 
} 

根據這本書,當我反序列化,一個新的ELVIS對象應當建立,但我看到的構造是不是在反序列化的時候叫什麼?

這裏是我的代碼序列化,並反序列化。

FileOutputStream fos = new FileOutputStream("myserial1.txt"); 
ObjectOutputStream oos = new ObjectOutputStream(fos); 
Elvis e = Elvis.getInstance(); 
System.out.println(" e = "+e.getInstance()); 

oos.writeObject(e); 

System.out.println("Serialization done."); 
FileInputStream fis = new FileInputStream("myserial1.txt"); 
ObjectInputStream ois = new ObjectInputStream(fis); 
Elvis el = (Elvis) ois.readObject(); 
System.out.println(" el = "+el.getInstance()); 

我看到e和e1都引用相同的引用,並且構造函數只被調用一次。

我在這裏誤解的概念?

請幫忙。

+0

非序列化意味着您可以多次執行此操作,這打破了單例的概念。這並不是說你不能做到這一點,但是你做了什麼就會成爲黑客。 –

+0

JBoss智能克隆似乎重用最終字段,也許這對你更好的選擇? http://www.jboss.org/serialization – KIC

回答

6

在系列化沒有構造函數被調用,(如果添加這個方法到類)的反序列化過程或readObject() method初始化領域。如果你想實現一個序列化的單,你應該還因爲它描述here添加readResolve()方法。


PS。
請注意,getInstance()是類別爲Elvis的靜態方法,因此諸如e.getInstance()el.getInstance()之類的調用等於Elvis.getInstance()

+0

- 「爲了維護單例保證,你必須聲明所有實例字段爲transient,並提供一個readResolve方法 (Item 77)。否則,每次一個序列化實例被反序列化,將創建一個新的實例 ,在我們的例子中,導致虛假的Elvis 目擊。爲了防止這種情況,請將此readResolve方法添加到Elvis類中。根據作者,如果我沒有實現readResolve(),單數是破碎的。但我看到它沒有壞掉,我得到了同樣的對象(引用是相同的)。這是我無法理解的。 – venkataratnam

+1

@venkataratnam 「但我看到它沒有壞掉,而且我得到了同樣的對象(引用是相同的)」。 沒有「readResolve()」方法「el」**是** **不是**與「e」相同,只是「Elvis.getInstance()」。你可以通過添加「System.out.println(el == e)」來測試它。在你的程序結束時。 –

+0

是的,你是對的.. el == e返回false。謝謝! – venkataratnam

1

我誤解的概念在這裏?

你誤解的是一個構造函數創建一個對象。不,它不。構造函數只是初始化對象。現在,反序列化不需要調用構造函數,因爲它已經具有序列化對象的狀態,而這正是它提供給我們的。但是,如果在可序列化類的層次結構中存在一些不可序列化的類,那麼它的構造函數將被調用以初始化該類中的狀態,因爲它尚未被序列化。

你可以通過Serialization Specification.

0
According to the book, when i deserialize, a new ELVIS object should be constructed, 
but i see the constructor is not called at the time of deserialization? 

首先是Object creation and constructor invocation are two separate thing。在正常情況下,當您使用new關鍵字創建對象時,首先創建Object,然後調用構造函數。您可以看到任何創建對象的Java類的字節碼。

現在對於你的問題,在Serialization對象像任何其他對象創建和而不是運行構造函數值是使用reflection恢復/狀態。所以基本上是從流中讀取值(持久存儲是你的情況)並使用反射注入到對象中。

+0

是的,只是不做最後的決定和使用Elvis.inst =(Elvis)ois.readObject();支持沒有構造函數被叫做!結果是:在elvis構造函數 中e = [email protected] 已完成序列化。 el = [email protected] – KIC

0

由於讀取和寫入操作都在同一個JVM實例和 類執行已經加載的讀操作和靜態字段店atclass水平所以在這裏永遠不需要靜態變量研究所進行重新實例化 public static final Elvis inst = new Elvis();

所以同樣的參考是與類級別相關的返回