tags:

views:

384

answers:

3

Dear all.

Unfortunately I haven't coded Java for about five years and I absolutely can not remember how or why the following code is working.

I stumbled across a similar example and broke it down to this. The emphasis is on the part below the comment: I don't get the constructor notation followed by the block in double brackets. And unfortunately I can not find anything in the java doc or by using google (what word(s) should I google?).

package syntaxtest;

public class Main {

    public static void main(String[] args) {

        // What kind of notation is this:
        MyTest tester = new MyTest() {{
            setName("John Johnson");
        }};

        System.out.println(tester.getName());
    }
}


class MyTest {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

So here are my questions:
1 How is this notation/ syntax called?
2 Where can I read some documentation about it?

I guess/ hope I will be able to answer the second question by myself if somebody can provide me with the answer to the first question.

To make it clear: I know the output is 'John Johnson'! ;) But I don't know why it is working!

However: any help is appreciated and many thanks in advance!

Yours.
dennis

+12  A: 

This is known as double brace initialization:

The first brace creates a new AnonymousInnerClass, the second declares an instance initializer block that is run when the anonymous inner class is instantiated. This type of initializer block is formally called an "instance initializer", because it is declared withing the instance scope of the class -- "static initializers" are a related concept where the keyword static is placed before the brace that starts the block, and which is executed at the class level as soon as the classloader completes loading the class (specified at http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.6) The initializer block can use any methods, fields and final variables available in the containing scope, but one has to be wary of the fact that initializers are run before constructors.

This only works only for non-final classes because it creates an anonymous subclass.

Andrew Hare
+12  A: 

Let's layout the code a bit differently:

MyTest tester = new MyTest() {
  {
    setName("John Johnson");
  }
};

What you see here is called double brace initialization. You have an anonymous inner subclass of class MyTest, along with an initializer block, which is a block that contains code that is run when the object is constructed.

Normally, you would put such code in the constructor, but since anonymous inner classes can't have constructors, this is the only way to guarantee the code is run when it's supposed to.

Having said that, it's a bit ugly to do this. There are better ways. However, I do use it myself on occasion, usually in the following idiom to create an immutable map:

final Map<String, Integer> textToInt = Collections.unmodifiableMap(new HashMap<String, Integer>() {{
    put("one", 1);
    put("two", 2);
    // etc
}});

Which creates a new map, overrides it, adds some values to it in the initializer block, and wraps it in an unmodifiable map.

jqno
A: 
MyTest tester = new MyTest() {{
   setName("John Johnson");
}};

is the same as

MyTest tester = new MyTest();
tester.setName("John Johnson");
Michael Angstadt
Those are not the same. Their results are not the same class. One creates an instance of MyTest. The other creates an instance of an anonymous subclass of MyTest. If your equals method looked like this: public boolean equals(Object other) { if( other.class != MyTest.class ) { return false; } //some more checks... }then it would fail to consider them the same.
CaptainAwesomePants
@mangst I think you should have said they are "Functionality equivilent for most purposes"; you have to be a little pedantic on here--nature of engineers and all...
Bill K