In the following code the getEntriesNotWorking
method reports a compile-time error:
public class DoubleBracketInitializerTest {
class Container {}
class Entry {
Container container;
public Entry(Container container) {
this.container = container;
}
}
class DetailedContainer extends Container {
List<Entry> getEntriesNotWorking() {
return new ArrayList<Entry>() {{
add(new Entry(this)); // compile-time error mentioned below
}};
}
List<Entry> getEntriesWorking() {
return Arrays.asList(new Entry(this));
}
}
}
Error:
The constructor DoubleBracketInitializerTest.Entry(new ArrayList(){}) is undefined
While the getEntriesWorking()
method is compiling correctly. The constructor is clearly there since a DetailedContailer
is a subclass of Contailer
.
What is the difference between those two methods, that makes the code invalid? How can I make the double bracket initializer work for this class hierarchy?
The problem is that within new ArrayList<Entry>() { ... }
, this
is an ArrayList<Entry>
. The clue is in the error message, which specifies which constructor signature it's looking for.
If you really want to use this sort of initialization, you want:
add(new Entry(DetailedContainer.this));
... to refer to the enclosing instance of DetailedContainer
.
I'd also strongly advise you to avoid inner classes unless you really need them. Life is a lot simpler when you only have top level classes, or nested static classes if you really need them.
I'd also avoid this sort of anonymous ArrayList
subclass construction - it's a lot more trouble than it's worth, IMO, compared with just creating the array list and adding the item. Or use Guava, with:
return Lists.newArrayList(new Entry(this));
Simpler all round!
See more on this question at Stackoverflow