舉例詳解Java編程中HashMap的初始化以及遍歷的方法
一、HashMap的初始化
1、HashMap 初始化的文藝寫法
HashMap 是一種常用的數(shù)據(jù)結(jié)構(gòu),一般用來做數(shù)據(jù)字典或者 Hash 查找的容器。普通青年一般會這么初始化:
HashMap<String, String> map =
new HashMap<String, String>();
map.put("Name", "June");
map.put("QQ", "2572073701");
看完這段代碼,很多人都會覺得這么寫太啰嗦了,對此,文藝青年一般這么來了:
HashMap<String, String> map =
new HashMap<String, String>() {
{
put("Name", "June");
put("QQ", "2572073701");
}
};
嗯,看起來優(yōu)雅了不少,一步到位,一氣呵成的趕腳。然后問題來了,有童鞋會問:納尼?這里的雙括號到底什么意思,什么用法呢?哈哈,其實(shí)很簡單,看看下面的代碼你就知道啥意思了。
public class Test {
/*private static HashMap< String, String> map = new HashMap< String, String>() {
{
put("Name", "June");
put("QQ", "2572073701");
}
};*/
public Test() {
System.out.println("Constructor called:構(gòu)造器被調(diào)用");
}
static {
System.out.println("Static block called:靜態(tài)塊被調(diào)用");
}
{
System.out.println("Instance initializer called:實(shí)例初始化塊被調(diào)用");
}
public static void main(String[] args) {
new Test();
System.out.println("=======================");
new Test();
}
}
輸出:
Static block called:靜態(tài)塊被調(diào)用 Instance initializer called:實(shí)例初始化被調(diào)用 Constructor called:構(gòu)造器被調(diào)用 ======================= Instance initializer called:實(shí)例初始化被調(diào)用 Constructor called:構(gòu)造器被調(diào)用
也就是說第一層括弧實(shí)際是定義了一個匿名內(nèi)部類 (Anonymous Inner Class),第二層括弧實(shí)際上是一個實(shí)例初始化塊 (instance initializer block),這個塊在內(nèi)部匿名類構(gòu)造時被執(zhí)行。這個塊之所以被叫做“實(shí)例初始化塊”是因?yàn)樗鼈儽欢x在了一個類的實(shí)例范圍內(nèi)。
上面代碼如果是寫在 Test 類中,編譯后你會看到會生成 Test$1.class 文件,反編譯該文件內(nèi)容:
D:\eclipse_indigo\workspace_home\CDHJobs\bin\pvuv\>jad -p Test$1.class
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. // Jad home page: http://www.kpdus.com/jad.html // Decompiler options: packimports(3) // Source File Name: Test.java
package pvuv.zhaopin;
import java.util.HashMap;
// Referenced classes of package pvuv.zhaopin:
// Test
class Test$1 extends HashMap // 創(chuàng)建了一個 HashMap 的子類
{
Test$1()
{ // 第二個 {} 中的代碼放到了構(gòu)造方法中去了
put("Name", "June");
put("QQ", "2572073701");
}
}
D:\eclipse_indigo\workspace_home\CDHJobs\bin\pvuv\>
2、推而廣之
這種寫法,推而廣之,在初始化 ArrayList、Set 的時候都可以這么玩,比如你還可以這么玩:
List<String> names = new ArrayList<String>() {
{
for (int i = 0; i < 10; i++) {
add("A" + i);
}
}
};
System.out.println(names.toString()); // [A0, A1, A2, A3, A4, A5, A6, A7, A8, A9]
3、Java7:增加對 collections 的支持
在 Java 7 中你可以像 Ruby, Perl、Python 一樣創(chuàng)建 collections 了。
Note:這些集合是不可變的。
PS:由于原文[5]作者并沒有標(biāo)出 java 7 哪個小版本號引入的這些新特性,對于留言報錯的同學(xué),請嘗試大于 1.7.0_09 或者 java8 試試?
List list = new ArrayList();
list.add("item");
String item = list.get(0);
Set< String> set = new HashSet< String>();
set.add("item");
Map< String, Integer> map = new HashMap< String, Integer>();
map.put("key", 1);
int value = map.get("key");
// 現(xiàn)在你還可以:
List< String> list = ["item"];
String item = list[0];
Set< String> set = {"item"};
Map< String, Integer> map = {"key" : 1};
int value = map["key"];
4、文藝寫法的潛在問題
文章開頭提到的文藝寫法的好處很明顯就是一目了然。這里來羅列下此種方法的壞處,如果這個對象要串行化,可能會導(dǎo)致串行化失敗。
1.此種方式是匿名內(nèi)部類的聲明方式,所以引用中持有著外部類的引用。所以當(dāng)串行化這個集合時外部類也會被不知不覺的串行化,當(dāng)外部類沒有實(shí)現(xiàn)serialize接口時,就會報錯。
2.上例中,其實(shí)是聲明了一個繼承自HashMap的子類。然而有些串行化方法,例如要通過Gson串行化為json,或者要串行化為xml時,類庫中提供的方式,是無法串行化Hashset或者HashMap的子類的,從而導(dǎo)致串行化失敗。解決辦法:重新初始化為一個HashMap對象:
new HashMap(map);
這樣就可以正常初始化了。
5、執(zhí)行效率問題
當(dāng)一種新的工具或者寫法出現(xiàn)時,猿們都會來一句:性能怎么樣?(這和男生談?wù)撁眉埖谝痪湟话愣际牵骸伴L得咋樣?三圍多少?”一個道理:))
關(guān)于這個兩種寫法我這邊筆記本上測試文藝寫法、普通寫法分別創(chuàng)建 10,000,000 個 Map 的結(jié)果是 1217、1064,相差 13%。
public class Test {
public static void main(String[] args) {
long st = System.currentTimeMillis();
/*
for (int i = 0; i < 10000000; i++) {
HashMap< String, String> map = new HashMap< String, String>() {
{
put("Name", "June");
put("QQ", "2572073701");
}
};
}
System.out.println(System.currentTimeMillis() - st); // 1217
*/
for (int i = 0; i < 10000000; i++) {
HashMap< String, String> map = new HashMap< String, String>();
map.put("Name", "June");
map.put("QQ", "2572073701");
}
System.out.println(System.currentTimeMillis() - st); // 1064
}
}
6、由實(shí)例初始化塊聯(lián)想到的一些變量初始化問題
從代碼上看,a 為什么可以不先聲明類型?你覺得 a、b、c 的值分別是多少?能說明理由么?
TIPS:如果你對這塊機(jī)制不了解,建議試著反編譯一下字節(jié)碼文件。
6.1 測試源碼
public class Test {
int e = 6;
Test() {
int c = 1;
this.f = 5;
int e = 66;
}
int f = 55;
int c = 11;
int b = 1;
{
a = 3;
b = 22;
}
int a = 33;
static {
d = 4;
}
static int d = 44;
int g = 7;
int h = 8;
public int test(){
g = 77;
int h = 88;
System.out.println("h - 成員變量:" + this.h);
System.out.println("h - 局部變量: " + h);
return g;
}
public static void main(String[] args) {
System.out.println("a: " + new Test().a);
System.out.println("b: " + new Test().b);
System.out.println("c: " + new Test().c);
System.out.println("d: " + new Test().d);
System.out.println("f: " + new Test().f);
System.out.println("e: " + new Test().e);
System.out.println("g: " + new Test().test());
}
}
6.2 字節(jié)碼反編譯:
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: Test.java
import java.io.PrintStream;
public class Test
{
Test()
{
this.e = 6;
f = 55;
this.c = 11;
b = 1;
a = 3;
b = 22;
a = 33;
g = 7;
h = 8;
int c = 1;
f = 5;
int e = 66;
}
public int test()
{
g = 77;
int h = 88;
System.out.println((new StringBuilder("h - \u6210\u5458\u53D8\u91CF\uFF1A")).append(this.h).toString());
System.out.println((new StringBuilder("h - \u5C40\u90E8\u53D8\u91CF: ")).append(h).toString());
return g;
}
public static void main(String args[])
{
System.out.println((new StringBuilder("a: ")).append((new Test()).a).toString());
System.out.println((new StringBuilder("b: ")).append((new Test()).b).toString());
System.out.println((new StringBuilder("c: ")).append((new Test()).c).toString());
new Test();
System.out.println((new StringBuilder("d: ")).append(d).toString());
System.out.println((new StringBuilder("f: ")).append((new Test()).f).toString());
System.out.println((new StringBuilder("e: ")).append((new Test()).e).toString());
System.out.println((new StringBuilder("g: ")).append((new Test()).test()).toString());
}
int e;
int f;
int c;
int b;
int a;
static int d = 4;
int g;
int h;
static
{
d = 44;
}
}
6.3 output:
a: 33
b: 22
c: 11
d: 44
f: 5
e: 6
h - 成員變量:8
h - 局部變量: 88
g: 77
二、HashMap遍歷方法示例
第一種:
Map map = new HashMap();
Iterator iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next(); Object key = entry.getKey();
Object val = entry.getValue();
}
效率高,以后一定要使用此種方式!
第二種:
Map map = new HashMap();
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
Object key = iter.next();
Object val = map.get(key);
}
效率低,以后盡量少使用!
HashMap的遍歷有兩種常用的方法,那就是使用keyset及entryset來進(jìn)行遍歷,但兩者的遍歷速度是有差別的,下面請看實(shí)例:
public class HashMapTest {
public static void main(String[] args) ...{
HashMap hashmap = new HashMap();
for (int i = 0; i < 1000; i ) ...{
hashmap.put("" i, "thanks");
}
long bs = Calendar.getInstance().getTimeInMillis();
Iterator iterator = hashmap.keySet().iterator();
while (iterator.hasNext()) ...{
System.out.print(hashmap.get(iterator.next()));
}
System.out.println();
System.out.println(Calendar.getInstance().getTimeInMillis() - bs);
listHashMap();
}
public static void listHashMap() ...{
java.util.HashMap hashmap = new java.util.HashMap();
for (int i = 0; i < 1000; i ) ...{
hashmap.put("" i, "thanks");
}
long bs = Calendar.getInstance().getTimeInMillis();
java.util.Iterator it = hashmap.entrySet().iterator();
while (it.hasNext()) ...{
java.util.Map.Entry entry = (java.util.Map.Entry) it.next();
// entry.getKey() 返回與此項(xiàng)對應(yīng)的鍵
// entry.getValue() 返回與此項(xiàng)對應(yīng)的值
System.out.print(entry.getValue());
}
System.out.println();
System.out.println(Calendar.getInstance().getTimeInMillis() - bs);
}
}
對于keySet其實(shí)是遍歷了2次,一次是轉(zhuǎn)為iterator,一次就從hashmap中取出key所對于的value。而entryset只是遍歷了第一次,他把key和value都放到了entry中,所以就快了。
注:Hashtable的遍歷方法和以上的差不多!
相關(guān)文章
SpringBoot實(shí)現(xiàn)API接口多版本支持的示例代碼
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)API接口多版本支持的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
java實(shí)現(xiàn)將數(shù)字轉(zhuǎn)換成人民幣大寫
前面給大家介紹過使用javascript,php,c#,python等語言實(shí)現(xiàn)人民幣大寫格式化,這篇文章主要介紹了java實(shí)現(xiàn)將數(shù)字轉(zhuǎn)換成人民幣大寫的代碼,非常的簡單實(shí)用,分享給大家,需要的朋友可以參考下2015-04-04
詳解spring-boot下如何滿足多生產(chǎn)環(huán)境中個性化定制功能
這篇文章主要介紹了詳解spring-boot下如何滿足多生產(chǎn)環(huán)境中個性化定制功能,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-03-03
java使用Filter實(shí)現(xiàn)自動登錄的方法
這篇文章主要為大家詳細(xì)介紹了java使用Filter實(shí)現(xiàn)自動登錄的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04
對arraylist中元素進(jìn)行排序?qū)嵗a
這篇文章主要介紹了對arraylist中元素進(jìn)行排序?qū)嵗a,還是比較不錯的,這里分享給大家,供需要的朋友參考。2017-11-11

