当前位置:首页 > 符号>正文

双括号,你可能没用过这种方式的集合

11-05 符号

双括号,你可能没用过这种方式的集合

关于【双括号】,你可能没用过这种方式的集合,今天黛儿小编给您分享一下,如果对您有所帮助别忘了关注本站哦。

 

<>()()〈〉‹›﹛﹜『』〖〗[]《》﹝﹞〔〕{}「」【】︵︶︷︸︿﹀︹︺︽︾﹁﹂﹃﹄︻︼

  • 推荐阅读:
  • 你可能没用过这种方式的集合!newHashMap(省略号)

来源:https://blog.csdn.net/luman1991/article/details/53034602

一、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 {        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.javapackage 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、文艺写法的潜在问题

文章开头提到的文艺写法的好处很明显就是一目了然。这里来罗列下此种方法的坏处,如果这个对象要串行化,可能会导致串行化失败。

  • 此种方式是匿名内部类的声明方式,所以引用中持有着外部类的引用。所以当串行化这个集合时外部类也会被不知不觉的串行化,当外部类没有实现serialize接口时,就会报错。
  • 上例中,其实是声明了一个继承自HashMap的子类。然而有些串行化方法,例如要通过Gson串行化为json,或者要串行化为xml时,类库中提供的方式,是无法串行化Hashset或者HashMap的子类的,从而导致串行化失败。

解决办法,重新初始化为一个HashMap对象:

new HashMap(map);

这样就可以正常初始化了。

4、执行效率问题

当一种新的工具或者写法出现时,猿们都会来一句:性能怎么样?(这和男生谈论妹纸第一句一般都是:“长得咋样?三围多少?”一个道理:))

关于这个两种写法我这边笔记本上测试文艺写法、普通写法分别创建 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>();            map.put("Name", "June");            map.put("QQ", "2572073701");        }        System.out.println(System.currentTimeMillis() - st); // 1064    }}

5、由实例初始化块联想到的一些变量初始化问题

从代码上看,a 为什么可以不先声明类型?你觉得 a、b、c 的值分别是多少?能说明理由么?TIP:如果你对这块机制不了解,建议试着反编译一下字节码文件。

5.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());    }}

5.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.javaimport 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; }}

5.3 输出结果:

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() {        HashMap hashmap = new 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的遍历方法和以上的差不多!

本文关键词:双括号《^o^》怎么打出来,双括号是什么符号,双括号在电脑上怎么打,双括号电脑键盘怎么打出来,双括号的用法。这就是关于《双括号,你可能没用过这种方式的集合》的所有内容,希望对您能有所帮助!更多的知识请继续关注我们!

版权声明: 本站仅提供信息存储空间服务,旨在传递更多信息,不拥有所有权,不承担相关法律责任,不代表本网赞同其观点和对其真实性负责。如因作品内容、版权和其它问题需要同本网联系的,请发送邮件至 举报,一经查实,本站将立刻删除。

猜你喜欢