Java map雙括號初始化方式的問題


關於Java雙括號的初始化凡是確實很方便,特別是在常量文件中,無可替代。如下所示:

Map map = new HashMap() {
  {
  put("Name", "Unmi");
  put("QQ", "1125535");
  }
};

好處很明顯就是一目了然。這里來羅列下此種方法的壞處,如果這個對象要串行化,可能會導致串行化失敗。

1.此種方式是匿名內部類的聲明方式(不懂的下文有詳盡解釋),所以引用中持有着外部類的引用。所以當時串行化這個集合時外部類也會被不知不覺的串行化,當外部類沒有實現serialize接口時,就會報錯。

2.上例中,其實是聲明了一個繼承自Hashset的子類。然而有些串行化方法,例如要通過Gson串行化為json,或者要串行化為xml時,類庫中提供的方式,是無法串行化Hashset或者HashMap的子類的,從而導致串行化失敗。解決辦法:重新初始化為一個Hashset對象:

new HashMap(map);

這樣就可以正常初始化了。

雙括號寫法的原理:

第一層括弧 實際是定義了一個內部匿名類 (Anonymous Inner Class),第二層括弧 實際上是一個實例初始化塊 (instance initializer block),這個塊在內部匿名類構造時被執行。這個塊之所以被叫做“實例初始化塊”是因為它們被定義在了一個類的實例范圍內。

上面代碼如果是寫在 TestDoubleBrace 類中,編譯后你會看到會生成 TestDoubleBrace$1.class 文件,反編譯該文件內容是:

final class com.unmi.TestDoubleBrace$1 extends java.util.HashMap{ //創建了一個 HashMap 的子類 TestDoubleBracke$1

  com.unmi.TestDoubleBrace$1();

Code:
  0: aload_0
  1: invokespecial #8; //Method java/util/HashMap."":()V //{} 中的代碼放到了構造方法中去了
  4: aload_0
  5: ldc #10; //String Name
  7: ldc #12; //String Unmi
  9: invokevirtual #14; //Method put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
  12: pop
  13: aload_0
  14: ldc #18; //String QQ
  16: ldc #20; //String 1125535
  18: invokevirtual #14; //Method put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
  21: pop
  22: return
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM