`
cgaolei
  • 浏览: 58210 次
  • 性别: Icon_minigender_1
  • 来自: 长春
社区版块
存档分类
最新评论

Java技巧之双括弧初始化

阅读更多

原文地址:http://www.c2.com/cgi/wiki?DoubleBraceInitialization

原作者:不详

译者:Alan Gao @ cgaolei.iteye.com

 

译者序:这是我在JavaIdioms(http://www.c2.com/cgi/wiki?JavaIdioms)上看到一个Java使用技巧。使用Java这么多年了,也还是头一次看到,还很实用。别看这小技巧好像很简单,但保证你不会在任何一书Java教材上看到,因为它不是一个真正的语法规范,而是一个语法的用法变种。小技巧还蕴含着Java的深层知识,就是身经百战的老手也不一定能说出其中奥妙。

 

翻译正文:

 

由于Java语言的集合框架中(collections, 如list, map, set等)没有提供任何简便的语法结构,这使得在建立常量集合时的工作非常繁索。每次建立时我们都要做:

  1. 定义一个临时的集合类变量
  2. 建立一个空集合的实例,然后赋值给变量
  3. 将数据放入集合中
  4. 最后将集合做为参数传递给方法

例如,要将一个Set变量传给一个方法:

 Set<String> validCodes = new HashSet<String>();
 validCodes.add("XZ13s");
 validCodes.add("AB21/X");
 validCodes.add("YYLEX");
 validCodes.add("AR2D");
 removeProductsWithCodeIn(validCodes);

也可以用静态初始的方法

 private static final Set<String> validCodes = new HashSet<String>();
 static {
        validCodes.add("XZ13s");
        validCodes.add("AB21/X");
        validCodes.add("YYLEX");
        validCodes.add("AR2D");
 }

其实,还有简结的方法,我们可以用双括弧语法(double-brace syntax)建立并初始化一个新的集合:

 private static final Set<String> VALID_CODES = new HashSet<String>() {{
        add("XZ13s");
        add("AB21/X");
        add("YYLEX");
        add("AR2D");
 }};

或者

 removeProductsWithCodeIn(new HashSet<String>() {{
        add("XZ13s");
        add("AB21/X");
        add("YYLEX");
        add("AR5E");
 }});

第一层括弧 实际是定义了一个内部匿名类 (Anonymous Inner Class),第二层括弧 实际上是一个实例初始化块 (instance initializer block),这个块在内部匿名类构造时被执行。这个块之所以被叫做“实例初始化块”是因为它们被定义在了一个类的实例范围内。这和“静态初始化块 (static initialzer)”不同,因为这种块在定义时在括弧前使用了static关键字,因此它的和类在同一个范围内的,也就是说当类加载时就会被执行(更详情,可参考Java语言规范http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.6 )。实例初始化块中可以使用其容器范围内的所有方法及变量,但特别需要注意的是实例初始化块是在构造器之前运行的。


这种方法只适用于不是final的类,因为final类是无法建立内部匿名子类,好在集合类都没有这个限制。因此,这种方法还可以被用来初始化其它任何对象,比如一个GUI对象:

 add(new JPanel() {{
        setLayout(...);
        setBorder(...);
        add(new JLabel(...));
        add(new JSpinner(...));
 }});

 这样建立的内部匿名类的实例中包函它容器对像的引用。如果串行化(serialization)这个集合同时也会串行化它的外部类。

分享到:
评论
43 楼 unsid 2009-07-14  
我更喜欢这种方式
dosomething(Arrays.asList(new String[]{"1","2","3"}));
不过只能用在List上

或者如果真是参数个数不确定,但是参数类型一样的话,不定参数更简洁
dosomething(String ...){}
dosomething(new String[]{"1","2","3"});
42 楼 unsid 2009-07-14  
相当于定义了一个继承HashMap并复写了初始化块的无名内隐类,很有用,尤其是在方法之间传递不确定参数或者返回不确定返回结果的时候。
41 楼 墓里活人 2009-07-14  
<div class="quote_title">cgaolei 写道</div>
<div class="quote_div">
<p>原文地址:http://www.c2.com/cgi/wiki?DoubleBraceInitialization</p>
<p>原作者:不详</p>
<p>译者:Alan Gao @ cgaolei.iteye.com</p>
<p> </p>
<p>译者序:这是我在JavaIdioms(http://www.c2.com/cgi/wiki?JavaIdioms)上看到一个Java使用技巧。使用Java这么多年了,也还是头一次看到,还很实用。别看这小技巧好像很简单,但保证你不会在任何一书Java教材上看到,因为它不是一个真正的语法规范,而是一个语法的用法变种。小技巧还蕴含着Java的深层知识,就是身经百战的老手也不一定能说出其中奥妙。</p>
<p> </p>
<p>翻译正文:  </p>
<p>由于Java语言的集合框架中(collections, 如list, map, set等)没有提供任何简便的语法结构,这使得在建立常量集合时的工作非常繁索。每次建立时我们都要做:</p>
<ol>
<li>定义一个临时的集合类变量</li>
<li>建立一个空集合的实例,然后赋值给变量</li>
<li>将数据放入集合中</li>
<li>最后将集合做为参数传递给方法</li>
</ol>
<p>例如,要将一个Set变量传给一个方法:</p>
<pre name="code" class="java"> Set&lt;String&gt; validCodes = new HashSet&lt;String&gt;();
validCodes.add("XZ13s");
validCodes.add("AB21/X");
validCodes.add("YYLEX");
validCodes.add("AR2D");
removeProductsWithCodeIn(validCodes);
</pre>
<p>也可以用静态初始的方法</p>
<pre name="code" class="java"> private static final Set&lt;String&gt; validCodes = new HashSet&lt;String&gt;();
static {
        validCodes.add("XZ13s");
        validCodes.add("AB21/X");
        validCodes.add("YYLEX");
        validCodes.add("AR2D");
}
</pre>
<p>其实,还有简结的方法,我们可以用双括弧语法(double-brace syntax)建立并初始化一个新的集合:</p>
<pre name="code" class="java"> private static final Set&lt;String&gt; VALID_CODES = new HashSet&lt;String&gt;() {{
        add("XZ13s");
        add("AB21/X");
        add("YYLEX");
        add("AR2D");
}};
</pre>
<p>或者</p>
<pre name="code" class="java"> removeProductsWithCodeIn(new HashSet&lt;String&gt;() {{
        add("XZ13s");
        add("AB21/X");
        add("YYLEX");
        add("AR5E");
}});
</pre>
<p><strong>第一层括弧</strong> 实际是定义了一个<span style="color: #ff0000;"><strong>内部匿名类</strong> </span>(Anonymous Inner Class),<strong>第二层括弧</strong> 实际上是一个<strong><span style="color: #ff0000;">实例初始化块</span> </strong>(instance initializer block),这个块在内部匿名类构造时被执行。这个块之所以被叫做“实例初始化块”是因为它们被定义在了一个类的实例范围内。这和“<span style="color: #ff0000;">静态初始化块</span> (static initialzer)”不同,因为这种块在定义时在括弧前使用了static关键字,因此它的和类在同一个范围内的,也就是说当类加载时就会被执行(更详情,可参考Java语言规范<a href="http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.6">http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.6</a> )。实例初始化块中可以使用其容器范围内的所有方法及变量,但特别需要注意的是实例初始化块是在构造器之前运行的。</p>
<p><br>这种方法只适用于不是final的类,因为final类是无法建立内部匿名子类,好在集合类都没有这个限制。因此,这种方法还可以被用来初始化其它任何对象,比如一个GUI对象:</p>
<pre name="code" class="java"> add(new JPanel() {{
        setLayout(...);
        setBorder(...);
        add(new JLabel(...));
        add(new JSpinner(...));
}});</pre>
<p> 这样建立的内部匿名类的实例中包函它容器对像的引用。<span style="color: #ff0000;">如果串行化(serialization)这个集合同时也会串行化它的外部类。</span> </p>
</div>
<p> </p>
40 楼 androidnew 2009-07-12  
恩。好,不错
学习了
39 楼 chandler 2009-07-10  
  我并不觉得后面两种有多好?
  匿名类觉得是一个很不伦不类的设计。
38 楼 topcss 2009-07-10  
学习了...
37 楼 mathfox 2009-07-09  
学习了,能少打不少字.

虽然eclipse提示这么多,还是少点好.
36 楼 libran 2009-07-09  
呵呵,学习了^_^
35 楼 lt0604 2009-07-08  
cgaolei 写道
mikewang 写道
您有的过时了, jdk1.2 刚刚问世的时候java。sun。com上就有过这种写法的介绍。

嗯,应该很早就有了,因为就是匿名内部类的应用。我还真没用这方法初始化过集合。后面GUI例子的方法倒是常用。。
温故知新呀。 

之前也在google中国上搜了下,没有找到中文关于这个说明,就翻译发出来了。JavaIdioms上还有很多其它的技巧,总还是有可学习的东西。

总结是要的,也是好的,学习的过程就是要不断的发现乐趣,享受乐趣。
但是我的项目组绝对不允许出现这样的代码!阐述完毕!
PS:今天看的很多mikewang的回复,发现你是不是和世人有仇呢?(我是忍无可忍了)
34 楼 niwei 2009-07-07  
惭愧,学java三年多还不知道有这种用法。
33 楼 troyconder 2009-07-06  
以前真不知道 谢谢楼主无私分享
32 楼 unika_ly12 2009-07-06  
mikewang 写道
您有的过时了, jdk1.2 刚刚问世的时候java。sun。com上就有过这种写法的介绍。


我刚刚知道,又学到一点。
31 楼 hsw168 2009-07-06  
没有用过。
试试看。。。
30 楼 clyman 2009-07-05  
谢谢楼主,前一阵在还为static final的集合怎么初始值烦恼呢
29 楼 dikar 2009-07-04  
说实话 我觉得这个功能不错,一般在写测试的时候向集合中塞数据的时候不错。简单,选择他适合的地方其实就是好的方法而不是乱用。
28 楼 ccyingfu 2009-07-04  
咦?!一不小心又学到新知识了!
不过我应该不太会用这样的方法!太不常规了,用着好迷糊!
27 楼 martinfans 2009-07-03  
不错。谢谢啦。
26 楼 whatwhat 2009-07-03  
双括号确实是一种简洁的初始化方式,
不过也小心它所引起的副作用
----
25 楼 containsoft 2009-07-03  
学习了。在实际中没这么用过。都是很规矩的写。
24 楼 youngbean 2009-07-03  
jmock2里面好像用的比较多

相关推荐

    Java双括弧初始化操作技巧

    Java双括弧初始化是一种在Java编程中用于简化集合框架(如List、Set、Map等)对象的创建和初始化的技巧。这种技术通过创建一个匿名内部类,并在其内部使用实例初始化块来填充集合对象,从而提高了代码的简洁性和...

    在java中 利用匿名内部类进行较简洁的双括弧初始化的方法

    本文将深入探讨如何在Java中利用匿名内部类进行双括弧初始化的方法。 首先,让我们理解什么是匿名内部类。匿名内部类是不具有名字的类,通常用于实现接口或继承一个类,并且仅在一个地方使用。它们的定义紧跟在它们...

    java在hashmap初始化时赋初值过程解析

    Java 在 HashMap 初始化时赋初值过程解析 ...本文介绍了 Java 中的 HashMap 初始化时赋初值过程解析,包括使用双括号进行初始化的语法和可能导致的串行化失败的问题,以及解决办法。希望对大家的学习有所帮助。

    DB查询分析器访问EXCEL时,要在表名前后加上中括弧或双引号

    【DB查询分析器访问EXCEL时,要在表名前后加上中括弧或双引号】 在数据库管理和数据分析领域,DB查询分析器是一款非常实用的工具,尤其对于处理多种数据库平台和非结构化数据如Excel文件时。《DB 查询分析器》是由...

    自定义括弧

    2. 初始化视图:在构造函数中,你可以设置默认属性,比如颜色、大小等,并重写必要的方法,如`onDraw()`,这是自定义绘图的关键。 ```java @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas...

    括弧匹配算法

    1. 初始化一个空栈。 2. 遍历输入字符串,对于每个字符: - 如果是开括号,将其压入栈中。 - 如果是闭括号,检查栈顶元素是否为它的匹配开括号: - 如果是,将栈顶元素弹出。 - 如果不是,或者栈为空,返回错误...

    java做的科学计算器(支持+-*/括号)

    Java编程实现的科学计算器是一个复杂而实用的项目,它不仅涉及到基本的加减乘除运算,还涵盖了更高级的数学功能,如括号处理和大数运算。在本项目中,开发者采用算符优先分析法来处理表达式的优先级,确保了计算的...

    自定义大括弧

    自定义视图通常需要重写构造函数,以设置必要的初始化参数。例如: ```java public CustomBracketView(Context context) { super(context); } public CustomBracketView(Context context, AttributeSet ...

    栈实现判断括弧匹配问题

    例如,可以定义一个数组作为栈空间,初始化一个栈顶指针,用于跟踪当前栈顶位置。当需要压栈时,栈顶指针加一,然后将元素存入对应位置;当需要弹栈时,栈顶指针减一,取出对应位置的元素。这样,我们就可以在程序中...

    办公自动化Axure RP8.0 标准课程括弧和半圆形.mp4

    办公自动化Axure RP8.0 标准课程括弧和半圆形.mp4

    算法-括弧匹配检验(信息学奥赛一本通-T1354)(包含源程序).rar

    1. 初始化一个空栈。 2. 遍历输入的括号字符串,遇到每个字符: - 如果是左括号('('、'['或'{'),将其压入栈中。 - 如果是右括号(')'、']'或'}'),检查栈顶元素是否为对应的左括号。如果是,弹出栈顶元素;...

    JAVA入门 日文版

    ### JAVA入门日文版知识点详解 #### 1. クラス(Class) - **クラスの定義**: クラスはオブジェクトの設計図であり、その設計図に基づいてインスタンス(オブジェクト)が生成されます。つまり、クラスはオブジェク...

    C++括弧匹配检验题解样例

    C++括弧匹配检验题解样例

    java.pdf

    随着时间的推移,Java发展迅速,现在已经成为全球开发者社区中最流行的语言之一,尤其在企业级应用开发中占有重要地位。 Java的发展历程可以从JDK 1.0追溯到最新的JDK 14。Java技术平台分为三个主要部分:Java ME...

    find_java.bat无法正常运行-16.09.21

    find_java.bat 无法正常运行,可能是两个原因造成的:1、路径中包含括弧等特殊字符;2、Windows API 函数 GetShortPathName 未能正常工作

    Java实现Andriod带看括弧的计算器代码

    本文将详细介绍如何使用Java语言实现这样一个功能丰富的计算器,包括处理括号、基本运算符以及数学函数。 首先,我们需要创建计算器的用户界面(UI)。在提供的代码片段中,可以看到XML布局文件定义了一个...

    Android应用源码可以运行括弧的科学计算器

    【Android应用源码可以运行括弧的科学计算器】是一个针对Android平台开发的源代码项目,旨在实现一个功能完善的科学计算器,特别强调了支持括号运算的功能。在Android开发中,创建这样的应用程序通常涉及到以下几个...

    mfc下括弧匹配(数据结构)

    该程序是针对数据结构实验在mfc下实现括弧匹配

    MFC数据结构算法实验括弧匹配问题

    1. 初始化一个空栈。 2. 遍历输入的括号序列。 3. 对于每个遍历到的括号: - 如果是打开括号,将其压入栈中。 - 如果是关闭括号,检查栈是否为空以及栈顶的括号是否与当前的关闭括号匹配。如果匹配,弹出栈顶元素...

Global site tag (gtag.js) - Google Analytics