1

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?

Dariusz
  • 21,561
  • 9
  • 74
  • 114

5 Answers5

5

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:

Community
  • 1
  • 1
Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
  • I thought that the double-bracket initialization is some kind of language-defined-new-in-java7 syntactic sugar for a collection initialization - instead it is an anonymous class with an instance initializer... – Dariusz Oct 17 '13 at 09:31
  • 1
    @Dariusz With an `instance initializer`. – Rohit Jain Oct 17 '13 at 09:31
3

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!

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
1

You can do like this.

class DetailedContainer extends Container {

    List<Entry> getEntriesNotWorking() {
        return new ArrayList<Entry>(Arrays.asList(new Entry(this)));
    }

    List<Entry> getEntriesWorking() {
        return Arrays.asList(new Entry(this));
    }

}
Prabhakaran Ramaswamy
  • 25,706
  • 10
  • 57
  • 64
1
return new ArrayList<Entry>() {{
                add(new Entry(this)); // compile-time error mentioned below
            }};

It seems you are creating Anonymous Class implementation, so this keyword inside the annonymous class refers to the object of type ArrayList. So, as there is not constructor for Entry class containing ArrayList as a argument available it gives compilation Error.

pnathan
  • 713
  • 3
  • 9
0
return new ArrayList<Entry>() {{
      add(new Entry(this)); // compile-time error mentioned below
}};

Try the following instead:

ArrayList<Entry> list = new ArrayList<Entry>();
list.add(new Entry(this));
return list;
desperateCoder
  • 700
  • 8
  • 18