Reputation: 9565
I know that this code:
Set<String> set = new HashSet<String>() {{
add("test1");
add("test2");
}};
is really:
Set<String> set = new HashSet<String>() {
{//initializer
add("test1");
add("test2");
}
};
The initializer block is being executed before the constructor block. In the above example, add("test1") is called before the constructor being executed. The constructor may be initializing many of the instance fields, so that this class would work. I am wondering why calling .add() before constructor would work? Is there any case that cause an issue?
Upvotes: 15
Views: 787
Reputation: 6675
There is a detail you left out that explains this.
First of all, let's review steps 3 through 5 of the initialization procedure (summarized):
3. the superclass constructor is called
4. the instance initializers are called
5. the body of the constructor is called
The detail that you've left out is that your expression is not simply creating a new instance of the HashSet
class, it is in fact creating a new instance of an anonymous subclass of HashSet
. (I believe this is specified in section 15.9.1.)
Since you did not declare a constructor, the default constructor is used. But before that, the constructor of the superclass HashSet
has completed.
So, in summary, the HashSet
constructor completes before your initializer block runs.
Upvotes: 17
Reputation: 36011
I consider this to be a bad practice because it creates pointless subclasses which can affect the memory usage and performance of the application. Anyway, the program is correct because the superclass constructor is called before the instance initializers. So when your initializer is run, the HashSet
constructor has run so the call to add
will work.
Upvotes: 3
Reputation: 13984
Instance initializers are executed just after the object is constructed. You are basically creating an inline extension of the HashSet and then "right after" it is created you are adding two items to it.
This is a common use pattern in mock objects for testing, such as in JMock, but also has other handy uses.
Hope this helps.
Upvotes: 4
Reputation: 21902
This assumption is wrong:
The initializer block is being executed before the constructor block.
Because in this particular case, the initializer block is part of the constructor block.
The docs state clearly that
The Java compiler copies initializer blocks into every constructor. Therefore, this approach can be used to share a block of code between multiple constructors.
I think you are confusing with static initializers.
Upvotes: 6