重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
Java 中HashMap初始化的另一种方式是怎么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
创新互联建站自2013年创立以来,是专业互联网技术服务公司,拥有项目网站制作、成都网站制作网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元桦南做网站,已为上家服务,为桦南各地企业和个人服务,联系电话:18980820575
如果你接触过不同的语言,从语法和代码层面来说,Java 是一种不折不扣的“臃肿、啰嗦”的语言,从另一方面来说这种臃肿和啰嗦也体现了它严谨的一面,作为适合构建大型、复杂项目的理由之一。
HashMap 是一种常用的数据结构,一般用来做数据字典或者 Hash 查找的容器。普通青年一般会这么初始化:
HashMapmap = new HashMap (); map.put("Name", "June"); map.put("QQ", "2572073701");
看完这段代码,很多人都会觉得这么写太啰嗦了,对此,文艺青年一般这么来了:
HashMapmap = new HashMap () { { put("Name", "June"); put("QQ", "2572073701"); } };
嗯,看起来优雅了不少,一步到位,一气呵成的赶脚。然后问题来了,有童鞋会问:纳尼?这里的双括号到底什么意思,什么用法呢?哈哈,其实很简单,看看下面的代码你就知道啥意思了。
public class Test { /*private static HashMapmap = new HashMap () { { 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(); } }
output:
Static block called:静态块被调用 Instance initializer called:实例初始化被调用 Constructor called:构造器被调用 ======================= Instance initializer called:实例初始化被调用 Constructor called:构造器被调用
Note:关于 static 的作用与用法如果不了解,请参考:
http://my.oschina.net/leejun2005/blog/193439#OSC_h4_1 为什么 main 方法是 public static void?
http://my.oschina.net/leejun2005/blog/144349#OSC_h4_2 设计模式之:聊聊 java 中的单例模式(Singleton)
也就是说第一层括弧实际是定义了一个匿名内部类 (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: 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_indigo\workspace_home\CDHJobs\bin\pvuv\>
这种写法,推而广之,在初始化 ArrayList、Set 的时候都可以这么玩,比如你还可以这么玩:
Listnames = new ArrayList () { { 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]
在 Java 7 中你可以像 Ruby, Perl、Python 一样创建 collections 了。
Note:这些集合是不可变的。
PS:由于原文[5]作者并没有标出 java 7 哪个小版本号引入的这些新特性,对于留言报错的同学,请尝试大于 1.7.0_09 或者 java8 试试?
Listlist = new ArrayList (); list.add("item"); String item = list.get(0); Set set = new HashSet (); set.add("item"); Map map = new HashMap (); map.put("key", 1); int value = map.get("key"); // 现在你还可以: List list = ["item"]; String item = list[0]; Set set = {"item"}; Map map = {"key" : 1}; int value = map["key"];
文章开头提到的文艺写法的好处很明显就是一目了然。这里来罗列下此种方法的坏处,如果这个对象要串行化,可能会导致串行化失败。
1.此种方式是匿名内部类的声明方式,所以引用中持有着外部类的引用。所以当时串行化这个集合时外部类也会被不知不觉的串行化,当外部类没有实现serialize接口时,就会报错。
2.上例中,其实是声明了一个继承自HashMap的子类。然而有些串行化方法,例如要通过Gson串行化为json,或者要串行化为xml时,类库中提供的方式,是无法串行化Hashset或者HashMap的子类的,从而导致串行化失败。解决办法:重新初始化为一个HashMap对象:
new HashMap(map);
这样就可以正常初始化了。
当一种新的工具或者写法出现时,猿们都会来一句:性能怎么样?(这和男生谈论妹纸第一句一般都是:“长得咋样?三围多少?”一个道理:))
关于这个两种写法我这边笔记本上测试文艺写法、普通写法分别创建 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++) { HashMapmap = new HashMap () { { put("Name", "June"); put("QQ", "2572073701"); } }; } System.out.println(System.currentTimeMillis() - st); // 1217 */ for (int i = 0; i < 10000000; i++) { HashMap map = new HashMap (); map.put("Name", "June"); map.put("QQ", "2572073701"); } System.out.println(System.currentTimeMillis() - st); // 1064 } }
从代码上看,a 为什么可以不先声明类型?你觉得 a、b、c 的值分别是多少?能说明理由么?
TIPS:如果你对这块机制不了解,建议试着反编译一下字节码文件。
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()); } }
// 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; } }
a: 33 b: 22 c: 11 d: 44 f: 5 e: 6 h - 成员变量:8 h - 局部变量: 88 g: 77
关于Java 中HashMap初始化的另一种方式是怎么问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注创新互联行业资讯频道了解更多相关知识。