Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

In Hidden Features of Java the top answer mentions Double Brace Initialization , with a very enticing syntax:

(在Java隐藏功能中 ,最佳答案提到了Double Brace Initialization ,它具有非常诱人的语法:)

Set<String> flavors = new HashSet<String>() {{
    add("vanilla");
    add("strawberry");
    add("chocolate");
    add("butter pecan");
}};

This idiom creates an anonymous inner class with just an instance initializer in it, which "can use any [...] methods in the containing scope".

(这个成语创建了一个匿名内部类,其中只包含一个实例初始化程序,“可以使用包含作用域中的任何[...]方法”。)

Main question: Is this as inefficient as it sounds?

(主要问题:这听起来效率低吗?)

Should its use be limited to one-off initializations?

(它的使用是否应限于一次性初始化?)

(And of course showing off!)

((当然炫耀!))

Second question: The new HashSet must be the "this" used in the instance initializer ... can anyone shed light on the mechanism?

(第二个问题:新的HashSet必须是实例初始化程序中使用的“this”...任何人都可以了解机制吗?)

Third question: Is this idiom too obscure to use in production code?

(第三个问题:在生产代码中使用这个成语是否过于模糊 ?)

Summary: Very, very nice answers, thanks everyone.

(简介:非常非常好的答案,谢谢大家。)

On question (3), people felt the syntax should be clear (though I'd recommend an occasional comment, especially if your code will pass on to developers who may not be familiar with it).

(在问题(3)中,人们认为语法应该是清楚的(尽管我建议偶尔发表评论,特别是如果你的代码会传递给可能不熟悉它的开发人员)。)

On question (1), the generated code should run quickly.

(在问题(1)上,生成的代码应该快速运行。)

The extra .class files do cause jar file clutter, and slow program startup slightly (thanks to @coobird for measuring that).

(额外的.class文件会导致jar文件混乱,并且会稍微减慢程序启动速度(感谢@coobird测量它)。)

@Thilo pointed out that garbage collection can be affected, and the memory cost for the extra loaded classes may be a factor in some cases.

(@Thilo指出垃圾收集可能会受到影响,在某些情况下,额外加载类的内存成本可能是一个因素。)

Question (2) turned out to be most interesting to me.

(问题(2)对我来说最有趣。)

If I understand the answers, what's happening in DBI is that the anonymous inner class extends the class of the object being constructed by the new operator, and hence has a "this" value referencing the instance being constructed.

(如果我理解答案,那么DBI中发生的事情是匿名内部类扩展了由new运算符构造的对象的类,因此具有引用正在构造的实例的“this”值。)

Very neat.

(井井有条。)

Overall, DBI strikes me as something of an intellectual curiousity.

(总的来说,DBI让我感到非常好奇。)

Coobird and others point out you can achieve the same effect with Arrays.asList, varargs methods, Google Collections, and the proposed Java 7 Collection literals.

(Coobird和其他人指出,您可以使用Arrays.asList,varargs方法,Google Collections和提议的Java 7 Collection文字获得相同的效果。)

Newer JVM languages like Scala, JRuby, and Groovy also offer concise notations for list construction, and interoperate well with Java.

(Scala,JRuby和Groovy等较新的JVM语言也为列表构建提供了简明的符号,并且与Java良好地互操作。)

Given that DBI clutters up the classpath, slows down class loading a bit, and makes the code a tad more obscure, I'd probably shy away from it.

(鉴于DBI使类路径混乱,减慢了类加载速度,并使代码更加模糊,我可能会回避它。)

However, I plan to spring this on a friend who's just gotten his SCJP and loves good natured jousts about Java semantics!

(但是,我打算在一位刚刚获得SCJP的朋友身上发表这篇文章,并且喜欢关于Java语义的好朋友!)

;-) Thanks everyone!

(;-) 感谢大家!)

7/2017: Baeldung has a good summary of double brace initialization and considers it an anti-pattern.

(7/2017:Baeldung对双支撑初始化有很好的总结 ,并认为它是一种反模式。)

12/2017: @Basil Bourque notes that in the new Java 9 you can say:

(12/2017:@Basil Bourque指出,在新的Java 9中你可以说:)

Set<String> flavors = Set.of("vanilla", "strawberry", "chocolate", "butter pecan");

That's for sure the way to go.

(这肯定是要走的路。)

If you're stuck with an earlier version, take a look at Google Collections' ImmutableSet .

(如果您遇到早期版本,请查看Google Collections的ImmutableSet 。)

  ask by Jim Ferrans translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
371 views
Welcome To Ask or Share your Answers For Others

1 Answer

Here's the problem when I get too carried away with anonymous inner classes:

(当我被匿名的内部类带走时,这就是问题所在:)

2009/05/27  16:35             1,602 DemoApp2$1.class
2009/05/27  16:35             1,976 DemoApp2$10.class
2009/05/27  16:35             1,919 DemoApp2$11.class
2009/05/27  16:35             2,404 DemoApp2$12.class
2009/05/27  16:35             1,197 DemoApp2$13.class

/* snip */

2009/05/27  16:35             1,953 DemoApp2$30.class
2009/05/27  16:35             1,910 DemoApp2$31.class
2009/05/27  16:35             2,007 DemoApp2$32.class
2009/05/27  16:35               926 DemoApp2$33$1$1.class
2009/05/27  16:35             4,104 DemoApp2$33$1.class
2009/05/27  16:35             2,849 DemoApp2$33.class
2009/05/27  16:35               926 DemoApp2$34$1$1.class
2009/05/27  16:35             4,234 DemoApp2$34$1.class
2009/05/27  16:35             2,849 DemoApp2$34.class

/* snip */

2009/05/27  16:35               614 DemoApp2$40.class
2009/05/27  16:35             2,344 DemoApp2$5.class
2009/05/27  16:35             1,551 DemoApp2$6.class
2009/05/27  16:35             1,604 DemoApp2$7.class
2009/05/27  16:35             1,809 DemoApp2$8.class
2009/05/27  16:35             2,022 DemoApp2$9.class

These are all classes which were generated when I was making a simple application, and used copious amounts of anonymous inner classes -- each class will be compiled into a separate class file.

(这些都是在我创建一个简单的应用程序时生成的类,并使用了大量的匿名内部类 - 每个类都将被编译成一个单独的class文件。)

The "double brace initialization", as already mentioned, is an anonymous inner class with a instance initialization block, which means that a new class is created for each "initialization", all for the purpose of usually making a single object.

(如前所述,“双括号初始化”是一个带有实例初始化块的匿名内部类,这意味着为每个“初始化”创建一个新类,所有这些都是为了通常制作单个对象。)

Considering that the Java Virtual Machine will need to read all those classes when using them, that can lead to some time in the bytecode verfication process and such.

(考虑到Java虚拟机在使用它们时需要读取所有这些类,这可能会导致字节码验证过程中出现一些时间等。)

Not to mention the increase in the needed disk space in order to store all those class files.

(更不用说为了存储所有这些class文件而增加所需的磁盘空间。)

It seems as if there is a bit of overhead when utilizing double-brace initialization, so it's probably not such a good idea to go too overboard with it.

(在使用双支撑初始化时似乎有一些开销,所以过分使用它可能不是一个好主意。)

But as Eddie has noted in the comments, it's not possible to be absolutely sure of the impact.

(但正如埃迪在评论中指出的那样,不可能完全确定其影响。)


Just for reference, double brace initialization is the following:

(仅供参考,双支撑初始化如下:)

List<String> list = new ArrayList<String>() {{
    add("Hello");
    add("World!");
}};

It looks like a "hidden" feature of Java, but it is just a rewrite of:

(它看起来像Java的“隐藏”功能,但它只是重写:)

List<String> list = new ArrayList<String>() {

    // Instance initialization block
    {
        add("Hello");
        add("World!");
    }
};

So it's basically a instance initialization block that is part of an anonymous inner class .

(所以它基本上是一个实例初始化块 ,它是匿名内部类的一部分 。)


Joshua Bloch's Collection Literals proposal for Project Coin was along the lines of:

(Joshua Bloch关于Project CoinCollection Literals提案遵循以下方针:)

List<Integer> intList = [1, 2, 3, 4];

Set<String> strSet = {"Apple", "Banana", "Cactus"};

Map<String, Integer> truthMap = { "answer" : 42 };

Sadly, it didn't make its way into neither Java 7 nor 8 and was shelved indefinitely.

(可悲的是,它没有进入Java 7和8,并被无限期搁置。)


Experiment

(实验)

Here's the simple experiment I've tested -- make 1000 ArrayList s with the elements "Hello" and "World!"

(这是我测试过的简单实验 - 使用"Hello""World!"元素制作1000个ArrayList 。)

added to them via the add method, using the two methods:

(使用以下两种方法通过add方法添加到它们:)

Method 1: Double Brace Initialization

(方法1:双支撑初始化)

List<String> l = new ArrayList<String>() {{
  add("Hello");
  add("World!");
}};

Method 2: Instantiate an ArrayList and add

(方法2:实例化ArrayListadd)

List<String> l = new ArrayList<String>();
l.add("Hello");
l.add("World!");

I created a simple program to write out a Java source file to perform 1000 initializations using the two methods:

(我创建了一个简单的程序来编写Java源文件,使用这两种方法执行1000次初始化:)

Test 1:

(测试1:)

class Test1 {
  public static void main(String[] s) {
    long st = System.currentTimeMillis();

    List<String> l0 = new ArrayList<String>() {{
      add("Hello");
      add("World!");
    }};

    List<String> l1 = new ArrayList<String>() {{
      add("Hello");
      add("World!");
    }};

    /* snip */

    List<String> l999 = new ArrayList<String>() {{
      add("Hello");
      add("World!");
    }};

    System.out.println(System.currentTimeMillis() - st);
  }
}

Test 2:

(测试2:)

class Test2 {
  public static void main(String[] s) {
    long st = System.currentTimeMillis();

    List<String> l0 = new ArrayList<String>();
    l0.add("Hello");
    l0.add("World!");

    List<String> l1 = new ArrayList<String>();
    l1.add("Hello");
    l1.add("World!");

    /* snip */

    List<String> l999 = new ArrayList<String>();
    l999.add("Hello");
    l999.add("World!");

    System.out.println(System.currentTimeMillis() - st);
  }
}

Please note, that the elapsed time to initialize the 1000 ArrayList s and the 1000 anonymous inner classes extending ArrayList is checked using the System.currentTimeMillis , so the timer does not have a very high resolution.

(请注意,使用System.currentTimeMillis检查初始化1000 ArrayList和扩展ArrayList的1000个匿名内部类所用的时间,因此计时器的分辨率不是很高。)

On my Windows system, the resolution is around 15-16 milliseconds.

(在我的Windows系统上,分辨率大约为15-16毫秒。)

The results for 10 runs of the two tests were the following:

(两次测试的10次运行的结果如下:)

Test1 Times (ms)           Test2 Times (ms)
----------------           ----------------
           187                          0
           203                          0
           203                          0
           188                          0
           188                          0
           187                          0
           203                          0
           188                          0
           188                          0
           203                          0

As can be seen, the double brace initialization has a noticeable execution time of around 190 ms.

(可以看出,双支撑初始化具有大约190ms的显着执行时间。)

Meanwhile, the ArrayList initialization execution time came out to be 0 ms.

(同时, ArrayList初始化执行时间为0毫秒。)

Of course, the timer resolution should be taken into account, but it is likely to be under 15 ms.

(当然,应该考虑定时器分辨率,但它可能不到15毫秒。)

So, there seems to be a noticeable difference in the execution time of the two methods.

(因此,两种方法的执行时间似乎有明显的差异。)

It does appear that there is indeed some overhead in the two initialization methods.

(看起来两个初始化方法确实存在一些开销。)

And yes, there were 1000 .class files generated by compiling the Test1 double brace initialization test program.

(是的,通过编译Test1双括号初始化测试程序生成了1000个.class文件。)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...