Java“双大括号初始化”的效率? [英] Efficiency of Java "Double Brace Initialization"?

查看:250
本文介绍了Java“双大括号初始化”的效率?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Java的隐藏功能中,顶部答案提及双大括号初始化,具有非常引诱语法:

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

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!)

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

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

第三个问题:这个成语在生产代码中是否也模糊

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

摘要:非常非常好的答案,感谢大家。问题(3),人们觉得语法应该清楚(虽然我建议偶尔的评论,特别是如果你的代码将传递给开发人员可能不熟悉它)。

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).

问题(1),生成的代码应该很快运行。额外的.class文件会导致jar文件混乱,并慢速程序启动稍微(感谢@coobird测量)。 @Thilo指出,垃圾回收可能会受到影响,额外加载的类的内存成本在某些情况下可能是一个因素。

On question (1), the generated code should run quickly. The extra .class files do cause jar file clutter, and slow program startup slightly (thanks to @coobird for measuring that). @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.

问题(2)对我来说是最有趣的。如果我理解答案,DBI发生的是,匿名内部类扩展了由new运算符构造的对象的类,因此有一个this值引用正在构造的实例。很整洁。

Question (2) turned out to be most interesting to me. 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. Very neat.

总的来说,DBI打击了我作为一个知识的好奇心。 Coobird和其他人指出,您可以使用Arrays.asList,varargs方法,Google Collections和建议的Java 7 Collection文字实现相同的效果。较新的JVM语言(如Scala,JRuby和Groovy)也为列表构建提供简洁的符号,并与Java良好互操作。鉴于DBI在类路径中混乱,减慢了类加载的速度,使得代码变得模糊不清,我可能会避开它。然而,我计划春天这个朋友谁刚刚得到他的SCJP和爱好性质的Java语义学习!

Overall, DBI strikes me as something of an intellectual curiousity. 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. Newer JVM languages like Scala, JRuby, and Groovy also offer concise notations for list construction, and interoperate well with 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. However, I plan to spring this on a friend who's just gotten his SCJP and loves good natured jousts about Java semantics! ;-) Thanks everyone!

推荐答案

这里有一个问题,当我厌with匿名内部类:

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.

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

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.

考虑到Java虚拟机在使用它们时需要读取所有这些类,这可能会导致字节码验证过程等。更不用说为了存储所有这些 class 文件所需的磁盘空间的增加。

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. Not to mention the increase in the needed disk space in order to store all those class files.

如果使用双括号初始化时有一点开销,所以它可能不是一个好主意,去太多了它。但是,正如Eddie在评论中指出的那样,不可能绝对确定其影响。

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.

双括号初始化如下:

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

看起来像Java的隐藏特性,但它只是一个重写: p>

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

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的集锦文字提案 for < a href =http://openjdk.java.net/projects/coin/ =nofollow noreferrer> Project Coin 符合以下条件:

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

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

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

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

很遗憾,没有在Java 7或8中执行,而且无限期地搁置。

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

实验

make 1000 ArrayList 与元素HelloWorld!通过添加方法添加到它们,使用两种方法:

Here's the simple experiment I've tested -- make 1000 ArrayLists with the elements "Hello" and "World!" added to them via the add method, using the two methods:

方法1 :双大括号初始化

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


$ b >和添加

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

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

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

测试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);
  }
}

测试2: / p>

Test 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);
  }
}

请注意,初始化1000 ArrayList s和使用 System.currentTimeMillis 检查扩展 ArrayList / code>,所以定时器没有非常高的分辨率。在我的Windows系统上,分辨率大约为15-16毫秒。

Please note, that the elapsed time to initialize the 1000 ArrayLists and the 1000 anonymous inner classes extending ArrayList is checked using the System.currentTimeMillis, so the timer does not have a very high resolution. On my Windows system, the resolution is around 15-16 milliseconds.

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

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

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

可以看出,双括号初始化具有大约190毫秒的显着执行时间。

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

同时, ArrayList 初始化执行时间出来为0 ms。当然,应该考虑定时器的分辨率,但它可能在15毫秒以下。

Meanwhile, the ArrayList initialization execution time came out to be 0 ms. Of course, the timer resolution should be taken into account, but it is likely to be under 15 ms.

所以,似乎有一个明显的执行时间的差异的两种方法。看起来确实有两个初始化方法有一些开销。

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.

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

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

这篇关于Java“双大括号初始化”的效率?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆