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

本文详细解析了Java中双括号初始化语法的特点及其应用场景,同时指出了在对象需要进行序列化时可能遇到的问题及解决方案。

关于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 
}

编写高质量代码 改善Java程序的151个建议 PDF高清完整版 http://www.linuxidc.com/Linux/2014-06/103388.htm

Java 8简明教程 http://www.linuxidc.com/Linux/2014-03/98754.htm

Java对象初始化顺序的简单验证 http://www.linuxidc.com/Linux/2014-02/96220.htm

Java对象值传递和对象传递的总结 http://www.linuxidc.com/Linux/2012-12/76692.htm

Java对象序列化ObjectOutputStream和ObjectInputStream示例 http://www.linuxidc.com/Linux/2012-08/68360.htm

本文永久更新链接地址http://www.linuxidc.com/Linux/2014-06/103535.htm

转载于:https://my.oschina.net/airship/blog/380815

<think>首先,用户的问题是关于JavaMap是否必须初始化问题是:“我想了解JavaMap是否必须初始化 请问Java Map是否需要初始化”。 根据系统级指令: - 所有行内数学表达式必须使用$...$格式,但在这个问题中,似乎没有数学表达式,所以不需要。 - 独立公式必须使用$$...$$格式并单独成段,但这里可能不需要。 - LaTeX语法正确:同样,可能不适用。 - 使用中文回答:所有回答必须用中文。 - 生成相关问题:在回答后添加相关问题部分。 - 回答中引用的段落末尾自然地添加引用标识:用户提供了引用[^1]和[^2],我需要参考它们。用户说:“上述引用仅供参考,并不是用户真正的需求,请尽可能多的参考用户上一次的问题和你的回答。” 但在这个对话中,这是第一条消息,所以没有上一次的问题。用户说:“请尽可能多的参考用户上一次的问题和你的回答”,但既然这是第一次,我应该基于提供的引用。 用户提供的引用: - 引用[1]: 关于Java初始化Map的两种方法。 - 引用[2]: 关于Java初始化Map的几种方式。 用户的问题是:“Java Map是否需要初始化”,意思是“Java Map是否需要被初始化”。 在Java中,Map是一个接口,不能直接实例化。你必须初始化一个具体的实现类,如HashMap、TreeMap等,否则使用未初始化Map会导致NullPointerException。 所以,回答的核心是:是的,Java Map必须初始化,因为Map是一个接口,需要实例化一个具体的实现。 现在,结构化回答: - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 步骤: 1. 直接回答问题Java Map需要初始化。 2. 解释原因:Map是接口,不能直接使用;必须创建对象。 3. 提供初始化方法:参考用户提供的引用。 4. 添加相关引用标识。 5. 生成相关问题。 回答大纲: - 开头:是的,在Java中,Map接口必须被初始化,否则在使用时会抛出NullPointerException。 - 原因:Map是一个接口,不能直接实例化。你需要创建一个实现了Map接口的具体类实例,如HashMap、TreeMap或LinkedHashMap。 - 初始化方法:参考用户提供的引用。 - 第一种方法:static块初始化(如引用[1])。 - 第二种方法:括号初始化(匿名内部类)(如引用[1])。 - 其他方法:直接初始化(如引用[2]提到的)。 - 强调重要性:如果不初始化,尝试调用Map的方法如put或get会导致NullPointerException。 - 添加引用:在相关段落末尾添加[^1]和[^2]。 - 结束:总结。 然后,生成相关问题。 相关问题部分:以“§§相关问题§§”开头,然后列出问题。 相关问题想法: 1. Java中如何正确初始化Map? 2. 什么是Map接口的常见实现类? 3. 如何避免NullPointerException当使用Map时? 4. JavaMap初始化最佳实践是什么? 5. Map初始化与性能有关吗? 确保回答用中文。 最终回答结构: - 回答部分。 - §§相关问题§§ - 相关问题列表。</think>### Java Map是否需要初始化? 是的,在Java中,Map接口必须被初始化Map本身是一个接口(定义在`java.util.Map`中),它不能被直接实例化。如果你声明一个Map变量但没有初始化(即没有分配具体对象),在运行时尝试调用其方法(如`put()`, `get()`)会抛出`NullPointerException`,因为未初始化Map引用默认为`null`[^1][^2]。初始化Map意味着创建一个实现了Map接口的具体类实例,例如`HashMap`, `TreeMap`或`LinkedHashMap`。这样可以确保Map对象在堆内存中被分配空间,并准备好存储键值对。 #### 为什么必须初始化? - **接口特性**:Map是接口,不是具体类。接口不能直接创建对象,必须通过实现类(如`new HashMap<>()`)来初始化[^2]。 - **避免NullPointerException**:未初始化Map变量是`null`,任何操作都会导致程序崩溃。例如: ```java Map<String, String> map; // 未初始化 map.put("key", "value"); // 运行时抛出NullPointerException ``` - **内存管理**:初始化过程分配内存空间,允许Map存储数据。如果不初始化Map无法使用。 #### 如何初始化Map? 参考Java常见实践,以下是几种初始化方法(基于用户提供的引用): 1. **静态块初始化**:适合在类加载时初始化静态Map。例如: ```java public class Demo { private static final Map<String, String> myMap; static { myMap = new HashMap<>(); myMap.put("a", "b"); myMap.put("c", "d"); } } ``` 这种方法线程安全,适用于常量Map[^1]。 2. **括号初始化(匿名内部类)**:简洁但可能影响性能(因为创建了匿名类)。例如: ```java Map<String, String> map = new HashMap<String, String>() {{ put("a", "b"); put("c", "d"); }}; ``` 注意:这种方式会生成额外类文件,不推荐在生产代码中大量使用[^1]。 3. **直接初始化**:最常见的方式,在声明时直接赋值。例如: ```java Map<String, String> map = new HashMap<>(); map.put("key1", "value1"); // 后续添加元素 ``` 或者使用Java 9+的工厂方法简化: ```java Map<String, String> map = Map.of("key1", "value1", "key2", "value2"); // 只读Map ``` 选择具体实现类(如`HashMap`用于快速访问,`TreeMap`用于排序)取决于需求[^2]。 #### 最佳实践 - **总是初始化**:在声明Map时立即初始化(如`Map<String, String> map = new HashMap<>();`),避免`null`风险。 - **考虑线程安全**:如果Map在多线程环境中使用,选择`ConcurrentHashMap`并正确初始化。 - **性能注意**:初始化时指定初始容量(如`new HashMap<>(16)`)可以优化性能,减少扩容开销。 总结:Java Map必须初始化,否则会导致运行时误。使用具体实现类(如`HashMap`)并选择合适的初始化方法,可以确保代码健壮性[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值