2011-06-15 59 views
5

我剛剛從一本java書籍學習網絡,所以我有點小菜鳥。我無法在書中或在網上找到這個問題,所以我決定詢問互聯網。(java)ObjectInputStream反序列化對象的錯誤版本

這本書說使用ObjectOutputStream和ObjectInputStream發送和接收對象到不同的控制檯。

現在,我能夠成功接收我發送的對象 - 但只有一次。當我發送不同的對象:隨機字符串和整數以及無名的實例時,控制檯具有所有正確的字段。但是,當我發送一個對象的實例時,更改其中一個實例字段的值並重新發送該對象,然後inpustream加載原始實例的值。例如,假設我有一個public int「var」等於1的類的實例。如果我發送這個類的實例,客戶端會收到它並正確地報告var = 1。但是, ,如果我將var更改爲2(在同一實例中)並重新發送,則客戶端將完成調用read()方法(因此它必須收到新對象!),但它會將var報告爲1。將實例發送給尚未收到實例的其他客戶端,它會正確地將var報告爲2,即使更改var,它也會繼續將其報告爲2。

客戶端讀取實例的正確版本(如果以前沒有收到它)的事實意味着該對象正在通過輸出流正確發送;由於某些原因輸入流只是不工作。它幾乎就像它看到它是同一個對象,所以它假定它沒有檢查就具有相同的值。爲什麼會發生這種情況,我該如何解決?

對不起,如果我問一些愚蠢的東西 - 本書沒有解釋序列化和套接字是如何工作的,只是如何使用它們,所以我很可能從根本上對如何使用它們感到困惑。謝謝!

簡單的代碼,我寫來測試問題:

服務器:(有計時器的動作來保持發送更新的對象)

public void actionPerformed(ActionEvent e) 
{ 
    object.var++; 
      output.write(object); 
      output.flush(); 
      System.out.println(object.var); 
} 

客戶

public void run() 
{ 
    while(true) 
      { 
        Test t = (Test)input.readObject(); 
        System.out.println(t.var); 
      } 
    } 

當這些程序運行服務器類的輸出是1,2,3,4 ...無限增加,而客戶端的輸出只是1,1,1,1,1,1,1等。

感謝您花時間閱讀本文。對不起,如果我只是愚蠢的,我是新來的這個東西。

編輯:對不起,讀()是由打字錯誤(我手動鍵入的代碼,因爲我不能eget正確的格式),我的意思是input.readObject()

+0

相關問題:http://stackoverflow.com/questions/15675262/。 – 2016-07-18 04:18:44

回答

-1

這麼多小時我已經花了調試這樣的代碼。 :)

我不知道什麼是適當的解決方案,但如果您創建對象的新實例,或者只是克隆它(),在發送它之前,代碼應該按預期工作。

看起來好像虛擬機識別它正在接收的對象是它已經擁有的對象,並且只是更新客戶端上的指針而不打擾實際檢查是否有任何更改。

嘗試...

public void actionPerformed(ActionEvent e) 
{ 
    object.var++; 
    //assuming your object supports clone() 
    output.write(object.clone()); 
    output.flush(); 
    System.out.println(object.var); 
} 
+1

一個小貨物崇拜節目永遠不會傷害,呃? – 2011-06-15 03:40:01

+0

經過足夠的時間在桌面上敲打頭部,試圖弄清楚爲什麼在服務器端打印所有字段會給您帶來與在客戶端打印所有字段不同的結果,加入邪教組織似乎是一個好主意。 ;) – Mike 2011-06-15 03:45:20

+4

'ObjectOutputStream.reset'是正確的解決方案:) – 2011-06-15 03:58:39

3

您是否使用從ObjectInputStream的read()readObject()?如果你使用read(),那麼你只是得到一個字節的數據。嘗試轉換客戶端

public void run() 
{ 
    while(true) 
    { 
    Test t = (Test)input.readObject(); 
    System.out.println(t.var); 
    } 
} 

編輯:應該已經input.readObject();

+0

你的意思是改變代碼爲'input.readObject()'? – Bohemian 2011-06-15 03:22:24

+0

是的......謝謝你看到我的疏忽。我將編輯。 – Suroot 2011-06-15 03:23:52

+0

謝謝你。 read()返回一個int是如此的誤導。把所有Java類型檢查浪費。 – navjotk 2013-12-05 11:59:59

12

原因是,ObjectOutputStream緩存對象引用並寫入對流的反向引用,如果相同的對象被寫入兩次。這意味着當您第二次調用write時,流實際上並未寫入對象的新副本,它只是插入對其已寫入的對象的引用。

您可以通過調用要寫入的調用之間的ObjectOutputStream.reset來阻止此操作。這告訴流放棄任何緩存的引用。

這種行爲似乎很奇怪,但如果您嘗試序列化具有循環引用的對象圖形(即寫入對象A引用對象B,然後引用對象A),則實際上有必要防止出現無限循環。

+0

這工作!謝謝! – superzipzop 2011-06-15 04:09:21

+0

不要忘記接受答案:)只需點擊您最喜歡的答案旁邊的複選標記。 – 2011-06-15 04:11:46

+0

你剛剛解決了我一直在努力工作數小時的問題!非常感謝! – 2013-11-20 05:59:21