歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

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
}

編寫高質量代碼 改善Java程序的151個建議 PDF高清完整版 http://www.linuxidc.com/Linux/2014-06/103388.htm

Java 8簡明教程 http://www.linuxidc.com/Linux/2014-03/98754.htm

Java對象初始化順序的簡單驗證 http://www.linuxidc.com/Linux/2014-02/96220.htm

Java對象值傳遞和對象傳遞的總結 http://www.linuxidc.com/Linux/2012-12/76692.htm

Java對象序列化ObjectOutputStream和ObjectInputStream示例 http://www.linuxidc.com/Linux/2012-08/68360.htm

Copyright © Linux教程網 All Rights Reserved