In Hidden Features of Java the top answer mentions Double Brace Initialization, with a very enticing syntax:
Set flavors = new HashSet
One property of this approach that has not been pointed out so far is that because you create inner classes, the whole containing class is captured in its scope. This means that as long as your Set is alive, it will retain a pointer to the containing instance (this$0
) and keep that from being garbage-collected, which could be an issue.
This, and the fact that a new class gets created in the first place even though a regular HashSet would work just fine (or even better), makes me not want to use this construct (even though I really long for the syntactic sugar).
Second question: The new HashSet must be the "this" used in the instance initializer ... can anyone shed light on the mechanism? I'd have naively expected "this" to refer to the object initializing "flavors".
This is just how inner classes work. They get their own this
, but they also have pointers to the parent instance, so that you can call methods on the containing object as well. In case of a naming conflict, the inner class (in your case HashSet) takes precedence, but you can prefix "this" with a classname to get the outer method as well.
public class Test {
public void add(Object o) {
}
public Set makeSet() {
return new HashSet() {
{
add("hello"); // HashSet
Test.this.add("hello"); // outer instance
}
};
}
}
To be clear on the anonymous subclass being created, you could define methods in there as well. For example override HashSet.add()
public Set makeSet() {
return new HashSet() {
{
add("hello"); // not HashSet anymore ...
}
@Override
boolean add(String s){
}
};
}