Meaning of New Class(...){{...}} Initialization Idiom

Meaning of new Class(...){{...}} initialization idiom

It's called double curly brace initialization. (EDIT: Link removed, archived here)

It means you're creating an anonymous subclass and the code within the double braces is basically a constructor. It's often used to add contents to collections because Java's syntax for creating what are essentially collection constants is somewhat awkward.

So you might do:

List<String> list = new ArrayList<String>() {{
add("one");
add("two");
add("three");
}};

instead of:

List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");

I actually don't like that and prefer to do this:

List<String> list = Arrays.asList("one", "two", "three");

So it doesn't make much sense in that case whereas it does for, say, Maps, which don't have a convenient helper.

Trouble in understanding this syntax

You are basically creating a anonymous class instance and specifying an instance initializer. Think of it in terms of a normal class, e.g.:

class Person {

String age, name;

List<String> hobbies;

{
hobbies = new ArrayList<String>();
}

public Person(String name, String age) {
this.name = name;
this.age = age;
}

}

What do you think the above is doing? Your anonymous class is doing something similar. :)

What's the difference between an instance initializer and a constructor?

The code inside the braces with no names will be part of the constructor of the class and be executed before the logic contained in the class constructor.

Quick example:

public class Foo {
{
System.out.println("Before Foo()");
}

public Foo() {
System.out.println("Inside Foo()");
}

{
System.out.println("Not After Foo()");
}
}

What does the {{ syntax on ArrayList initializer really do

You are creating a new anonymous subclass of ArrayList, with an instance initializer which calls add() twice.

It's the same as:

class MyList extends ArrayList
{

{ // This is an instance initializer; the code is invoked before the constructor.
add("first");
add("second");
}

public MyList() {
super();
// I believe initializers run here, but I have never specifically tested this
}
}

...

List list=new MyList();

Note that, personally, I do not advise it as an idiom, since it will lead to class-file explosion.

Strange syntax in ArrayList declaration in java

This creates an anonymous class with a custom initializer (see Initializing Instance Members):

Normally, you would put code to initialize an instance variable in a constructor. There are two alternatives to using a constructor to initialize instance variables: initializer blocks and final methods.
Initializer blocks for instance variables look just like static initializer blocks, but without the static keyword:

{
// whatever code is needed for initialization goes here
}

It's convient when you want a list with members already in it, but produces more code when compiled because the anonymous class is actually compiled to a (global) class different that extends ArrayList.

I've recently read this post which is relevant to the matter:

The first point to note is that the Java runtime has no understanding of inner classes at all. Whether the inner class is named or anonymous, a smoke-and-mirrors procedure is used to convert the inner class to a global class. If the class has a name, then the compiler generates class files whose names have the format [outer]$[inner] — $ is a legal identifier in Java. For inner classes, the generated class files are simply numbered. So when the Thread example at the start of this article is compiled, we end up with a class file called Test$1.class. The number '1' indicates that this is the first anonymous class defined within the class Test.

What is Double Brace initialization in Java?

Double brace initialisation creates an anonymous class derived from the specified class (the outer braces), and provides an initialiser block within that class (the inner braces). e.g.

new ArrayList<Integer>() {{
add(1);
add(2);
}};

Note that an effect of using this double brace initialisation is that you're creating anonymous inner classes. The created class has an implicit this pointer to the surrounding outer class. Whilst not normally a problem, it can cause grief in some circumstances e.g. when serialising or garbage collecting, and it's worth being aware of this.

Initialization-on-demand holder idiom - When are classes loaded?

The exact time when a class is initialized, is specified in the Java® Language Specification, §12.4.1

§12.4.1. When Initialization Occurs

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

  • T is a class and an instance of T is created.
  • A static method declared by T is invoked.
  • A static field declared by T is assigned.
  • A static field declared by T is used and the field is not a constant variable (§4.12.4).
  • T is a top level class (§7.6) and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.

When a class is initialized, its superclasses are initialized (if they have not been previously initialized), as well as any superinterfaces (§8.1.5) that declare any default methods (§9.4.3) (if they have not been previously initialized). Initialization of an interface does not, of itself, cause initialization of any of its superinterfaces.

The last bullet has been removed in Java 9

The time of class loading is not that fixed and may depend on implementation details, e.g. how the verifier has been implemented. But obviously, it has to happen before the initialization.

From the JVM’s point of view, the fact that this is a nested class has no special relevance. There is a symbolic reference to the inner class in the outer class’ constant pool, like there is for any other referenced class. It will be resolved when needed.

Block Statements in Java

This:

MyMap m = new MyMap() {
....
};

creates an anonymous inner class, which is a subclass of HashMap.

This:

{
put("some key", "some value");
}

is an instance initializer. The code is executed when the instance of the anonymous subclass is created.

Double brace initialization in JRuby

I don't think there is a way to do double curly brace initialization in JRuby. But for things like ArrayList Initialization JRuby offers shortcuts as in example below.

Please check https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby for details.

>> a = ArrayList.new [:a, :b, "c", "d"]
#<Java::JavaUtil::ArrayList:0x65a953>
>> a[0]
:a
>> a[1]
:b
>> a[2]
"c"
>> a[3]
"d"
>> a[4]
nil


Related Topics



Leave a reply



Submit