• Java map双括号初始化方式的问题


    关于Java双括号的初始化凡是确实很方便,特别是在常量文件中,无可替代。如下所示:

    Map map = new HashMap() {
      {
      put("Name", "Unmi");
      put("QQ", "1125535");
      }
    };

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

    1.此种方式是匿名内部类的声明方式(不懂的下文有详尽解释),所以引用中持有着外部类的引用。所以当时串行化这个集合时外部类也会被不知不觉的串行化,当外部类没有实现serialize接口时,就会报错。

    2.上例中,其实是声明了一个继承自Hashset的子类。然而有些串行化方法,例如要通过Gson串行化为json,或者要串行化为xml时,类库中提供的方式,是无法串行化Hashset或者HashMap的子类的,从而导致串行化失败。解决办法:重新初始化为一个Hashset对象:

    new HashMap(map);

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

    双括号写法的原理:

    第一层括弧 实际是定义了一个内部匿名类 (Anonymous Inner Class),第二层括弧 实际上是一个实例初始化块 (instance initializer block),这个块在内部匿名类构造时被执行。这个块之所以被叫做“实例初始化块”是因为它们被定义在了一个类的实例范围内。

    上面代码如果是写在 TestDoubleBrace 类中,编译后你会看到会生成 TestDoubleBrace$1.class 文件,反编译该文件内容是:

    final class com.unmi.TestDoubleBrace$1 extends java.util.HashMap{ //创建了一个 HashMap 的子类 TestDoubleBracke$1

      com.unmi.TestDoubleBrace$1();

    Code:
      0: aload_0
      1: invokespecial #8; //Method java/util/HashMap."":()V //{} 中的代码放到了构造方法中去了
      4: aload_0
      5: ldc #10; //String Name
      7: ldc #12; //String Unmi
      9: invokevirtual #14; //Method put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
      12: pop
      13: aload_0
      14: ldc #18; //String QQ
      16: ldc #20; //String 1125535
      18: invokevirtual #14; //Method put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
      21: pop
      22: return
    }

  • 相关阅读:
    【BZOJ3166】ALO(主席树)
    【UOJ#188】Sanrd(min_25筛)
    伯努利数
    【51Nod1258】序列求和V4(FFT)
    【BZOJ5306】[HAOI2018]染色(NTT)
    【BZOJ4943】【NOI2017】蚯蚓排队(哈希)
    【BZOJ4912】天才黑客(最短路,虚树)
    【BZOJ5333】荣誉称号(动态规划)
    NOI2018前的每日记录
    【BZOJ1088】扫雷(递推)
  • 原文地址:https://www.cnblogs.com/kabi/p/8066421.html
Copyright © 2020-2023  润新知