2009-10-05 46 views
3

我有以下問題:匿名類的二進制名

1)有與存儲在A的靜態字段有兩個匿名子類之間循環依賴幾個匿名子類一些抽象的A級。該抽象類的代碼類似於以下內容:

class A implements Serializable 
{ 
    public static final A _1 = new A() { 
     public A foo() 
     { 
      return _2; 
     } 
    }; 

    public static final A _2 = new A() { 
     public A foo() 
     { 
      return _1; 
     } 
    }; 

    public static final A _3 = new A() { 
     public void bar() 
     { 
      // do something 
     } 
    }; 
} 

2)類A的實例被序列化中使用的其他對象引用。有一些對象被開發者預先序列化,然後作爲二進制數據包含在發行版中。

在發佈版本中更改了匿名子類的A類二進制名稱的一些重構之後。我認爲這可能是由於java編譯器版本的差異。從我機器上創建的.class文件中,我可以看到存儲在_1,_2和_3字段中的A的匿名子類分別具有名稱A $ 1,A $ 2和A $ 3,但是從發佈版本獲取的.class文件中,我可以看到存儲在_1,_2和_3字段中的A的匿名子類分別具有名稱A $ 2,A $ 3和A $ 1。由於這個預先序列化的數據變得無法使用,我需要以某種方式解決這個問題。

是否有任何java編譯器或JVM的規範,它會說我應該對我的匿名類有什麼樣的二進制名稱? JLS表示匿名類的名稱應該是封閉類的名稱,「$」 - 不對這些序列設置任何約束的符號和非空序列。

我相信我不應該依賴匿名類的內部名稱,我也知道「正確的」方法來解決這個問題,比如在構建服務器上生成預序列化的數據。太糟糕了,我們現在沒有太多時間來解決這個問題,所以我想知道這個命名差異來自哪裏,所以我現在可以解決這個問題。

回答

1

我可以猜出爲什麼它失敗的唯一原因是新的Java版本重新排列類名,因爲您在_1中引用_2。也就是說,我不認爲你可以依賴這些名字,因爲Java並沒有確定它將按照何種順序處理一個類的字段(因此,它將創建內部類的順序)。

但我認爲你的問題在別的地方。你會得到什麼錯誤?

+0

在A $ 1類的反序列化過程中,出現「本地類不兼容」異常。發生這種情況是因爲名稱A $ 1的類定義與序列化期間的類定義不同。 – okutane

+0

在這種情況下,[本文] [http://www.informit.com/articles/article.aspx?p=31936]可能會有所幫助。 –

+0

是的,這是編譯器的差異。然而,我還沒有想出它...... – okutane

4

我敢挑戰一些元素嗎?希望這能對你有用:

  1. 如果你希望你的類有一個著名的名字......嗯,匿名是一個名爲類的相反! ;-)
  2. preserializing和交付對象作爲二進制數據是一個危險的選擇,你被它咬了(在重構過程中,但我相信這可能發生在許多其他條件)。序列化數據通常被認爲是Java中的短期解決方案,可以持續幾秒鐘。許多其他選項可用於長期存儲。現在

,如果要求解決短期的問題,我看到的唯一方法是你的類恢復到與以前的版本兼容的狀態。如果您提到的不同順序是唯一的區別,我相信定義匿名類的順序與以前相同,值得嘗試!還要注意引用應該是向後的(對於文件中較早的一個類),而不是向前傳遞(稍後在文件中向類傳遞)。

+0

我不關注你對後向引用的評論嗎?你的意思是靜態初始化命令的問題? /非瞬時序列化可以完成,但是如果你對它進行一些預先考慮,它會變得更容易。 –

+0

@Tom是的,向後引用避免了靜態初始化的一些問題。但是,**的東西附加在您閱讀它們的順序**中,當您試圖獲得精確的訂單時,這非常重要:-) – KLE

1

你的編譯器沒有給出任何警告?

我相信你可以通過覆蓋ObjectInputStream.readClassDescriptor來讀取數據而不依賴於當前代碼中的匿名類名。替換爲「兼容」類的描述符。沒有保證可以工作,但如果您的數據很重要,可能值得一試。