天天看點

聊聊 Java 中 HashMap 初始化的另一種方式

如果你接觸過不同的語言,從文法和代碼層面來說,java 是一種不折不扣的“臃腫、啰嗦”的語言,從另一方面來說這種臃腫和啰嗦也展現了它嚴謹的一面,作為适合建構大型、複雜項目的理由之一。

1、hashmap 初始化的文藝寫法

hashmap 是一種常用的資料結構,一般用來做資料字典或者 hash 查找的容器。普通青年一般會這麼初始化:

看完這段代碼,很多人都會覺得這麼寫太啰嗦了,對此,文藝青年一般這麼來了:

嗯,看起來優雅了不少,一步到位,一氣呵成的趕腳。然後問題來了,有童鞋會問:納尼?這裡的雙括号到底什麼意思,什麼用法呢?哈哈,其實很簡單,看看下面的代碼你就知道啥意思了。

note:關于 static 的作用與用法如果不了解,請參考:

也就是說第一層括弧實際是定義了一個匿名内部類 (anonymous inner class),第二層括弧實際上是一個執行個體初始化塊 (instance initializer block),這個塊在内部匿名類構造時被執行。這個塊之是以被叫做“執行個體初始化塊”是因為它們被定義在了一個類的執行個體範圍内。

上面代碼如果是寫在 test 類中,編譯後你會看到會生成 test$1.class 檔案,反編譯該檔案内容:

2、推而廣之

這種寫法,推而廣之,在初始化 arraylist、set 的時候都可以這麼玩,比如你還可以這麼玩:

3、java7:增加對 collections 的支援

在 java 7 中你可以像 ruby, perl、python 一樣建立 collections 了。

note:這些集合是不可變的。

ps:由于原文[5]作者并沒有标出 java 7 哪個小版本号引入的這些新特性,對于留言報錯的同學,請嘗試大于 1.7.0_09 或者 java8 試試?

4、文藝寫法的潛在問題

文章開頭提到的文藝寫法的好處很明顯就是一目了然。這裡來羅列下此種方法的壞處,如果這個對象要串行化,可能會導緻串行化失敗。

1.此種方式是匿名内部類的聲明方式,是以引用中持有着外部類的引用。是以當時串行化這個集合時外部類也會被不知不覺的串行化,當外部類沒有實作serialize接口時,就會報錯。

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

new hashmap(map);

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

5、執行效率問題

當一種新的工具或者寫法出現時,猿們都會來一句:性能怎麼樣?(這和男生談論妹紙第一句一般都是:“長得咋樣?三圍多少?”一個道理:))

關于這個兩種寫法我這邊筆記本上測試文藝寫法、普通寫法分别建立 10,000,000 個 map 的結果是 1217、1064,相差 13%。

6、由執行個體初始化塊聯想到的一些變量初始化問題

從代碼上看,a 為什麼可以不先聲明類型?你覺得 a、b、c 的值分别是多少?能說明理由麼?

tips:如果你對這塊機制不了解,建議試着反編譯一下位元組碼檔案。

6.1 測試源碼

6.2 位元組碼反編譯:

6.3 output:

7、refer: