4 ms·
Watch out - double-brace initialization is cool looking, but it's orders of magnitude slower than regular initialization as it must generate an anonymous class.
by ZitchDog 17y ago
Watch out - double-brace initialization is cool looking, but it's orders of magnitude slower than regular initialization as it must generate an anonymous class.
Also, the generated class is put into the permgen space, which is not garbage collected. The permgen is pretty small by default - and if you fill it up, your system is hosed.
I use them all the time in unit tests, but never in production code.
- jrockway 17y agoInteresting. Even in Perl we cache and garbage-collect anon classes. (The caching is for the very common case of creating a subclass with optional roles applied: my $class = Some::Meta::Class->create_anon_class( superclasses => ['Foo'], roles => [qw/Commonly Applied Traits/], ); There is almost no speed hit the second time you create an instance of "Foo" with "Commonly", "Applied", and "Traits" applied. Not sure this would be useful for Java, although we can achieve the same effect as in the article.)
- sunkencity 17y agoperl has a more stable vm than java :) I like this trick though, it will help me with my seaside clone in java :)
- jrockway 17y agoFWIW, this is all done in "user space". The metaclass instance is attached to every instance that it creates. When all the instances go away, there are no more references to the metaclass, and it gets reclaimed. The destructor handles deleting the symbol table entries that were added, and that's that. There is something to be said for not baking things into the language.
- scotth 17y agoThe compiler generates the anonymous class. To the runtime, isn't it just a class with a name given to it by the compiler, not a developer (question mark...my key broke today) It's true that it uses up permgen though, but if it only adds an initializer we're not talking about much space. Edit: I did an experiment. This is the code: new ArrayList<Object>() { {} }; new ArrayList<Object>(); Here is the bytecode: 0 new Main$1 [16] 3 invokespecial Main$1() [18] 6 new java.util.ArrayList [19] 9 invokespecial java.util.ArrayList() [21] And, the class: class Main$1 extends java.util.ArrayList { // Method descriptor #6 ()V // Stack: 1, Locals: 1 Main$1(); 0 aload_0 [this] 1 invokespecial java.util.ArrayList() [8] 4 return Line numbers: [pc: 0, line: 10] [pc: 4, line: 1] Local variable table: [pc: 0, pc: 5] local: this index: 0 type: new Main(){} Just a regular old subclass.
- brown9-2 17y agoSeems wasteful, just to save a few keystrokes.
- cschneid 17y agoIt's pretty useful in unit tests, since it very clearly lays out the sample data you'll be comparing. I rarely if ever used it in the production code.
- deleted 17y ago[deleted]
- ubernostrum 17y agoThis is one case where I really prefer C#'s approach; it supports a shortcut syntax (works on anything which implements IEnumerable and has a public Add method): List<int> intList = new List<int>() { 1, 2, 3 }; which involves no anonymous classes or anything of the sort. The compiler merely "expands" it into the following before producing the bytecode: List<int> intList = new List<int>(); intList.Add(1); intList.Add(2); intList.Add(3); Which is, really, about what I'd expect such a shortcut syntax to do.
- deleted 17y ago[deleted]
- dangravell 17y agoI think just generally you have to be aware that it is not a concrete ArrayList (or whatever) that is being created. You have to be careful about which classes you are anonymously subclassing. If the superclass has an equals method, for instance, that follows the getClass().equals(compare.getClass()) approach as part of its logic you are screwed.
- wlievens 17y agoAnd it can break equals() if you're not careful.