java双括弧初始化

01. Map map = new HashMap() {{
02. put( "Name" , "Unmi" );
03. put( "QQ" , "1125535" );
04. }};
05.
06. List stooges = new ArrayList() {{
07. add( "Larry" );
08. add( "Moe" );
09. add( "Curly" );
10. }};


看起来都是在一条语句里完成,而不需要分步骤写成:

1. Map map = new HashMap();
2. map.put( "Name" , "Unmi" );
3. map.put( "QQ" , "1125535" );


一 不小心没好好理解的人可能以为它是什么特别的语法,关键是大括号连一块了,原作者也是在故作姿态,美其名曰:双括弧语法(double-brace syntax)。真是乱花渐欲迷人眼,其实就是匿名类加初始块。该文有解释:第一层括弧 实际是定义了一个内部匿名类 (Anonymous Inner Class),第二层括弧 实际上是一个实例初始化块 (instance initializer block),这个块在内部匿名类构造时被执行。

那怎么去更好理解它呢?如果我们写成如下的方式应该会更好理解吧,提个技巧,在 Eclipse 中对第一段代码按下 Ctrl + Shift + F 就如下了:

1. Map map = new HashMap() {
2. {
3. put( "Name" , "Unmi" );
4. put( "QQ" , "1125535" );
5. }
6. };


其 实就是匿名类啊,会创建出一个 HashMap 的子类来,匿名类中一个 {} 括起来的初始化块,里面自然可放置初始化代码。{} 块中的代码编译后会放到 <init>(),也就是构造方法中去,所以可用来初始化实例。如果是写在 TestDoubleBrace 类中,编译后你会看到会生成 TestDoubleBrace$1.class 文件,反编译该文件内容是:

01. final class com.unmi.TestDoubleBrace$1 extends java.util.HashMap{ //创建了一个 HashMap 的子类 TestDoubleBracke$1
02. com.unmi.TestDoubleBrace$1();
03. Code:
04. 0: aload_0
05. 1: invokespecial #8; //Method java/util/HashMap."<init>":()V //{} 中的代码放到了构造方法中去了
06. 4: aload_0
07. 5: ldc #10; //String Name
08. 7: ldc #12; //String Unmi
09. 9: invokevirtual #14; //Method put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
10. 12: pop
11. 13: aload_0
12. 14: ldc #18; //String QQ
13. 16: ldc #20; //String 1125535
14. 18: invokevirtual #14; //Method put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
15. 21: pop
16. 22: return
17.
18. }


所以说白了,什么双括弧语法啊,就是代码写得不规范,才使得那么的令人费解。如果还不能理解,再列两个惯用代码来:

01. JFrame frame = new JFrame();
02. frame.addMouseListener( new MouseAdapter() {
03. public void mouseClicked(MouseEvent e) {
04. // do womething here.
05. }
06. });
07.
08. Thread thread = new Thread() {{ // 也学着样把大括号也连一块写了
09. this .setName( "作业处理线程" );
10. } // 如果不重新定义 run() 方法,那么后面那个大括号也能与这个并一块
11.
12. public void run() {
13. // do something here.
14. }
15. };
16. thread.start();


应该没问题了吧,上面是事件监听器和多线程常用的写法,如果他不把大括号连在一起,而是规范的写代码,相信您一开始也不会对所谓的 Double Brace Syntax 有太多的困惑。要说这种初始化方法运用到集合中还挺方便的,只是无端的多了些匿名类。

刚 开始我看到这种双括符写法也是把它奉若圣经,对它只一知半解,昨天在用 XStream 把一个对象生成 XML 文件时,其中有一个 List 属性,我就借用了这种双括符法来初始化元素,结果生成的 XML 文件走了样,原因是 XStream 的 Converter 能处理 ArrayList,但无法很好的处理生成的 ArrayList 的匿名子类。因此才回头认真的重新审视了一番这个所谓的双括符初始化语法。





参考:

http://www.iteye.com/topic/412868

http://www.blogjava.net/Unmi/archive/2009/08/12/290845.html

http://www.iteye.com/topic/418542
### 初始容量设置 在Java中,`List`和`Map`的初始容量设置对于性能优化非常重要。默认情况下,`ArrayList`的初始容量为10,而`HashMap`的初始容量为16。这些默认值可以在不指定容量的情况下自动调整,但在某些情况下,手动设置初始容量可以提高性能并减少内存浪费。 #### `List`的初始容量 对于`ArrayList`,如果在创建时没有指定初始容量,则会使用默认值10。当向`ArrayList`中添加元素时,如果当前容量不足以容纳新元素,它会自动扩容。扩容机制通常是将当前容量增加一半(即新的容量变为原来的1.5倍)[^2]。 ```java List<String> list = new ArrayList<>(20); // 设置初始容量为20 ``` #### `Map`的初始容量 对于`HashMap`,默认的初始容量是16,并且负载因子为0.75。这意味着当`HashMap`中的元素数量超过16 * 0.75 = 12时,`HashMap`会进行扩容操作。扩容时,`HashMap`会重新哈希所有键值对到一个新的桶数组中,这可能会导致一定的性能开销。因此,在已知数据量较大的情况下,建议提前设置合适的初始容量和负载因子以避免频繁扩容[^3]。 ```java Map<String, String> map = new HashMap<>(32); // 设置初始容量为32 ``` ### 初始化配置 除了设置初始容量外,还可以通过构造函数或方法来初始化集合的内容。例如,使用括号`{{}}`语法可以快速初始化一个匿名内部类,其中包含一些预定义的数据。 #### 使用括号初始化 括号初始化的第一层括弧用于定义一个匿名内部类,第二层括弧则是一个实例初始化块,该块在内部匿名类构造时被执行。这种方式常用于快速初始化集合对象[^1]。 ```java List<String> list = new ArrayList<>() {{ add("item1"); add("item2"); }}; ``` 同样地,也可以用于初始化`Map`对象: ```java Map<String, String> map = new HashMap<>() {{ put("name", "test"); put("age", "20"); }}; ``` 虽然这种方法非常方便,但它会产生额外的类文件并且可能导致内存泄漏,因为匿名内部类持有外部类的引用。因此,在生产环境中应谨慎使用这种技术。 ### 相关问题 1. 如何选择合适的负载因子以优化`HashMap`的性能? 2. 在什么情况下应该手动设置`ArrayList`的初始容量? 3. 括号初始化是否存在潜在的问题?如何避免这些问题? 4. `HashMap`和`HashSet`在扩容机制上有何不同? 5. 是否可以通过其他方式替代括号初始化来实现集合的快速初始化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值