举例详解Java编程中HashMap的初始化以及遍历的方法

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

举例详解Java编程中HashMap的初始化以及遍历的⽅法⼀、HashMap的初始化
1、HashMap 初始化的⽂艺写法
HashMap 是⼀种常⽤的数据结构,⼀般⽤来做数据字典或者 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");
}
};
嗯,看起来优雅了不少,⼀步到位,⼀⽓呵成的赶脚。

然后问题来了,有童鞋会问:纳尼?这⾥的双括号到底什么意思,什么⽤法呢?哈哈,其实很简单,看看下⾯的代码你就知道啥意思了。

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:构造器被调⽤");
}
static {
System.out.println("Static block called:静态块被调⽤");
}
{
System.out.println("Instance initializer called:实例初始化块被调⽤");
}
public static void main(String[] args) {
new Test();
System.out.println("=======================");
new Test();
}
}
输出:
Static block called:静态块被调⽤
Instance initializer called:实例初始化被调⽤
Constructor called:构造器被调⽤
=======================
Instance initializer called:实例初始化被调⽤
Constructor called:构造器被调⽤
也就是说第⼀层括弧实际是定义了⼀个匿名内部类 (Anonymous Inner Class),第⼆层括弧实际上是⼀个实例初始化块(instance initializer block),这个块在内部匿名类构造时被执⾏。

这个块之所以被叫做“实例初始化块”是因为它们被定义在了⼀个类的实例范围内。

上⾯代码如果是写在 Test 类中,编译后你会看到会⽣成 Test$1.class ⽂件,反编译该⽂件内容:
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: /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 // 创建了⼀个 HashMap 的⼦类
{
Test$1()
{ // 第⼆个 {} 中的代码放到了构造⽅法中去了
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 ⼀样创建 collections 了。

Note:这些集合是不可变的。

PS:由于原⽂[5]作者并没有标出 java 7 哪个⼩版本号引⼊的这些新特性,对于留⾔报错的同学,请尝试⼤于 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");
// 现在你还可以:
List< String> list = ["item"];
String item = list[0];
Set< String> set = {"item"};
Map< String, Integer> map = {"key" : 1};
int value = map["key"];
4、⽂艺写法的潜在问题
⽂章开头提到的⽂艺写法的好处很明显就是⼀⽬了然。

这⾥来罗列下此种⽅法的坏处,如果这个对象要串⾏化,可能会导致串⾏化失败。

1.此种⽅式是匿名内部类的声明⽅式,所以引⽤中持有着外部类的引⽤。

所以当串⾏化这个集合时外部类也会被不知不觉的串⾏化,当外部类没有实现serialize接⼝时,就会报错。

2.上例中,其实是声明了⼀个继承⾃HashMap的⼦类。

然⽽有些串⾏化⽅法,例如要通过Gson串⾏化为json,或者要串⾏化为xml时,类库中提供的⽅式,是⽆法串⾏化Hashset或者HashMap的⼦类的,从⽽导致串⾏化失败。

解决办法:重新初始化为⼀个HashMap对象:
new HashMap(map);
这样就可以正常初始化了。

5、执⾏效率问题
当⼀种新的⼯具或者写法出现时,猿们都会来⼀句:性能怎么样?(这和男⽣谈论妹纸第⼀句⼀般都是:“长得咋样?三围多少?”⼀个道理:))
关于这个两种写法我这边笔记本上测试⽂艺写法、普通写法分别创建 10,000,000 个 Map 的结果是 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、由实例初始化块联想到的⼀些变量初始化问题
从代码上看,a 为什么可以不先声明类型?你觉得 a、b、c 的值分别是多少?能说明理由么?TIPS:如果你对这块机制不了解,建议试着反编译⼀下字节码⽂件。

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 字节码反编译:
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: /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来进⾏遍历,但两者的遍历速度是有差别的,下⾯请看实例:
 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() 返回与此项对应的键
// entry.getValue() 返回与此项对应的值
System.out.print(entry.getValue());
}
System.out.println();
System.out.println(Calendar.getInstance().getTimeInMillis() - bs);
}
}
对于keySet其实是遍历了2次,⼀次是转为iterator,⼀次就从hashmap中取出key所对于的value。

⽽entryset只是遍历了第⼀次,他把key和value都放到了entry中,所以就快了。

注:Hashtable的遍历⽅法和以上的差不多!。

相关文档
最新文档