用于实例化内部类的奇怪语法

时间:2009-03-11 06:56:10

标签: java constructor inner-classes

我没想到在这个阶段我会再遇到Java的全新语法,但是,我刚刚遇到了一些问题:

确切的上下文以及下面代码应该做的事情是非常无关紧要的 - 它只是提供某种上下文。

我正在尝试在IT Mill Toolkit中综合创建一个事件,所以我写了这样一行:

buttonClick(new Button.ClickEvent(button));

但是,Eclipse给出了以下错误消息:

  

无法访问类型为Button的封闭实例。必须使用Button类型的封闭实例限定分配(例如x.new A(),其中x是Button的实例)。

当我按如下方式重写上面一行时,它不会再抱怨了:

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

所以,我的问题是:后面的语法是什么意思,确切地说,为什么第一个代码片段不起作用?什么是Java抱怨,以及它在第二个版本中做了什么?

背景信息:ButtonButton.ClickEvent都是非抽象的公共类。

6 个答案:

答案 0 :(得分:69)

内部类(如Button.ClickEvent)需要引用外部类的实例(Button)。

该语法创建Button.ClickEvent的新实例,其外部类引用设置为button的值。

这是一个例子 - 忽略缺少封装等,它只是为了演示的目的:

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();
    }
}

有关内部类和封闭实例的更多信息,请参阅section 8.1.3 of the spec

答案 1 :(得分:9)

Button.ClickEvent是一个非静态内部类,因此该类的实例只能包含在Button的实例中。

在你的第二个代码示例中,你有一个Button实例,你创建了一个ClickEvent实例,包含在这个Button实例中...

答案 2 :(得分:8)

Java中的非静态内部类包含一个隐藏引用,该引用指向它声明的外部类的实例。因此,您最初获得的错误消息告诉您无法创建内部类的新实例不指定要附加到的外部类的实例。

也许你之前没有看到过这种语法的原因是内部类经常在外部类的方法中分配,编译器会自动处理它。

答案 3 :(得分:3)

为了避免让自己和程序员混淆这个很少使用的功能,你总是可以使内部类静态。

如果需要引用外部类,可以在构造函数中显式传递它。

答案 4 :(得分:1)

你实际上可以做到,但你必须在ClickEvent内声明 staticButton ,然后你就不应该使用sintax时遇到任何问题:

buttonClick(new Button.ClickEvent(button));

基本上static会使班级ClickEvent直接属于班级Button,而不属于new Button()的特定实例(即Button)。

关注@Jon Skeet示例:

// 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) {
    }
}

答案 5 :(得分:-1)

如果输入了

,您的代码就会编译
buttonClick(new Button().ClickEvent(button));

而不是

buttonClick(new Button.ClickEvent(button));

作为构造函数是一种方法,当您在Java中调用方法时,您必须传递参数列表,即使它是空的。