Reputation: 67703
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.
Upvotes: 43
Views: 17460
Reputation: 19027
You actually can do that, but you have to declare ClickEvent
as static
inside Button
, and then you shouldn't have any problem using you sintax:
buttonClick(new Button.ClickEvent(button));
Basically static
makes the class ClickEvent
belong directly to the class Button
instead of a specific instance(i.e. new Button()
) of Button
.
Following @Jon Skeet example:
// Button.java
class Button
{
public static class ClickEvent
{
public ClickEvent(Button b)
{
System.out.println("Instance: " + this.toString());
}
}
}
// Test.java
public class Test
{
public static void main(String[] args)
{
Button button = new Button();
buttonClick(new Button.ClickEvent(button));
}
public static void buttonClick (Button.ClickEvent ce) {
}
}
Upvotes: 2
Reputation: 12770
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 second code example you have an instance of Button and you create an instance of ClickEvent enclosed in this Button instance...
Upvotes: 10
Reputation: 7620
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.
Upvotes: -1
Reputation: 56772
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.
Upvotes: 3
Reputation: 116674
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.
Upvotes: 9
Reputation: 1500575
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.
Upvotes: 71