views:

1308

answers:

5

I didn't imagine that I would encounter radically new syntax in Java anymore at this stage, but lo and behold, I just encountered something:

The exact context and what the code below should do is pretty irrelevant - it's there just to give some kind of context.

I'm trying to synthetically create an event in IT Mill Toolkit, so I wrote this kind of line:

buttonClick(new Button.ClickEvent(button));

But, Eclipse gives me the following error message:

No enclosing instance of type Button is accessible. Must qualify the allocation with an enclosing instance of type Button (e.g. x.new A() where x is an instance of Button).

When I rewrite the line above as follows, it doesn't complain anymore:

buttonClick(button.new ClickEvent(button)); // button instanceof Button

So, my question is: What does the latter syntax mean, exactly, and why doesn't the first snippet work? What is Java complaining about, and what's it doing in the second version?

Background info: Both Button and Button.ClickEvent are non-abstract public classes.

+5  A: 

Button.ClickEvent is a non-static inner class so an instance of this class can only exist enclosed in a instance of Button.

In your secons code example you have an instance of Button and you create an instance of ClickEvent enclosed in this Button instance...

pgras
+28  A: 

Inner classes (like Button.ClickEvent) need a reference to an instance of the outer class (Button).

That syntax creates a new instance of Button.ClickEvent with its outer class reference set to the value of button.

Here's an example - ignore the lack of encapsulation etc, it's just for the purposes of demonstration:

class Outer
{
    String name;

    class Inner
    {
        void sayHi()
        {
            System.out.println("Outer name = " + name);
        }
    }
}

public class Test
{
    public static void main(String[] args)
    {
        Outer outer = new Outer();
        outer.name = "Fred";

        Outer.Inner inner = outer.new Inner();
        inner.sayHi();
    }
}

See section 8.1.3 of the spec for more about inner classes and enclosing instances.

Jon Skeet
If the inner class doesn't need the reference to the outer class to function, you can eliminate this requirement by using the static keyword in the inner class declaration - static class Inner in the above example - though obviously you would then not have access to the Outer.name property...!
Bill Michell
+4  A: 

A non-static inner class in Java contains a hidden reference that points to an instance of the outer class it is declared in. So the error message you got originally is telling you that you cannot create a new instance of the inner class without also specifying an instance of the outer class for it to be attached to.

Perhaps the reason you haven't seen that syntax before is that inner classes are often allocated in a method of the outer class, where the compiler takes care of this automatically.

Daniel Earwicker
A: 

To avoid confusing yourself and fellow programmers with this rarely-used feature you can always make inner classes static.

In case a reference to the outer class is needed you can pass it explicitly in the constructor.

starblue
Or make inner classes private, and stick to the implicit this.
Tom Hawtin - tackline
A: 

Your code would compile, had you typed

buttonClick(new Button().ClickEvent(button));

instead of

buttonClick(new Button.ClickEvent(button));

as a constructor is a method and when you call a method in Java you must pass the list of arguments, even when it is empty.

DanTe
Actually, no, that doesn't work, because it tries to call the method ClickEvent(Button) with that, which it doesn't find...
Henrik Paul
new Button().new ClickEvent(button) ?
Tom Hawtin - tackline