new HashMap(){{put(key, value);}}的解释
来源:互联网 发布:淘宝怎么获得天猫积分 编辑:程序博客网 时间:2024/06/05 20:29
一、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_indigoworkspace_homeCDHJobsbinpvuv>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 // 创建了一个 HashMap 的子类
- {
- Test$1()
- { // 第二个 {} 中的代码放到了构造方法中去了
- put("Name", "June");
- put("QQ", "2572073701");
- }
- }
D:eclipse_indigoworkspace_homeCDHJobsbinpvuv>
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: 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 - u6210u5458u53D8u91CFuFF1A")).append(this.h).toString());
- System.out.println((new StringBuilder("h - u5C40u90E8u53D8u91CF: ")).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的遍历方法和以上的差不多!
- new HashMap(){{put(key, value);}}的解释
- new HashMap(){{put("id", "001");}}的解释
- HashMap put(K key, V value)解析
- new HashMap().put(key,value)返回值为null,已解决
- HashMap中的put(Object key, Object value)方法实现
- HashMap.put(K key, V value)源码分析
- HashMap遍历 key value
- HashMap和HashTable,HashMap中key和value的原理
- HashMap和HashTable,HashMap中key和value的原理
- HashMap和HashTable,HashMap中key和value的原理
- java HashMap的put
- HashMap的put()方法
- HashMap 根据Value获取Key
- HashMap按key/value排序
- HashMap根据value获取key
- 关于hashMap的key和value的理解
- HashMap 的遍历key与value的方法
- HashMap 的遍历key与value的方法 .
- 看门狗(一)
- 小知识_Android
- 使用idea将maven项目打包war文件部署到tomcat
- ConcurrentHashMap summary
- Myeclipse基本设置
- new HashMap(){{put(key, value);}}的解释
- cast of Objective-C pointer type 'NSString *' to C pointer type 'CFStringRef' (aka 'const struct __C
- HTML140种常用RGB颜色代码列表
- 1*1+2*2+...n*n和1*1*1+2*2*2+...+n*n*n和公式推导
- 无需客户端扫描局域网抓取返回信息
- 哈夫曼树->哈夫曼编码
- JavaScript实现的9大排序算法
- JDBC连接数据库的方式
- 共享内存(进程通信)