43

我没想到在这个阶段我会在 Java 中遇到全新的语法,但是你瞧,我只是遇到了一些事情:

确切的上下文和下面的代码应该做什么是无关紧要的——它只是为了提供某种上下文。

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

buttonClick(new Button.ClickEvent(button));

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

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

当我如下重写上面的行时,它不再抱怨了:

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

所以,我的问题是:后一种语法到底是什么意思,为什么第一个片段不起作用?Java 在抱怨什么,在第二个版本中它在做什么?

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

4

6 回答 6

71

内部类(如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();
    }
}

有关内部类和封闭实例的更多信息,请参阅规范的第 8.1.3 节。

于 2009-03-11T07:02:07.200 回答
10

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

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

于 2009-03-11T07:00:56.440 回答
9

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

也许您以前没有见过这种语法的原因是内部类通常分配在外部类的方法中,编译器会自动处理这个问题。

于 2009-03-11T07:05:33.603 回答
3

为了避免让你自己和其他程序员对这个很少使用的特性感到困惑,你总是可以让内部类成为静态的。

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

于 2009-03-11T09:29:24.290 回答
2

您实际上可以这样做,但是您必须声明ClickEventstaticinside Button,然后使用您的 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) {
    }
}
于 2016-02-15T14:43:08.350 回答
-1

如果您键入,您的代码将编译

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

代替

buttonClick(new Button.ClickEvent(button));

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

于 2009-03-11T10:20:42.183 回答