Search code examples
javacollectionscollection-initializer

Undefined constructor error in a double bracket collection initializer


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?


Solution

  • The double-braces initialization:

    return new ArrayList<Entry>() {{
                add(new Entry(this)); // compile-time error mentioned below
            }};
    

    creates an anonymous inner class, which is a subclass of ArrayList<Entry> in this case. So, the this reference refers to an instance of the subclass of ArrayList<Entry> and not the DetailedContainer . To get the this reference of DetailedContainer class current instance, use DetailedContainer.this

    return new ArrayList<Entry>() {{
                add(new Entry(DetailedContainer.this));  
            }};
    

    Of course, if you don't want a fixed sized list, you can directly use:

    return new ArrayList<Entry>(Arrays.asList(new Entry(this)));
    

    instead of anonymous class. That is lot easier to understand.


    See also: