Странный синтаксис для создания экземпляров внутреннего класса

Я не предполагал, что на этом этапе я столкнусь с принципиально новым синтаксисом в 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 и что она делает во второй версии?

Справочная информация: оба Button а также Button.ClickEvent неабстрактные публичные классы.

6 ответов

Решение

Внутренние классы (как 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 спецификации для получения дополнительной информации о внутренних классах и включающих их экземплярах.

Button.ClickEvent является нестатическим внутренним классом, поэтому экземпляр этого класса может существовать только в экземпляре Button.

Во втором примере кода у вас есть экземпляр Button, и вы создаете экземпляр ClickEvent, заключенный в этот экземпляр Button...

Нестатический внутренний класс в Java содержит скрытую ссылку, которая указывает на экземпляр внешнего класса, в котором он объявлен. Таким образом, сообщение об ошибке, которое вы получили изначально, говорит вам, что вы не можете создать новый экземпляр внутреннего класса, не указав также экземпляр внешнего класса, к которому он должен быть присоединен.

Возможно, причина того, что вы еще не видели этот синтаксис, заключается в том, что внутренние классы часто размещаются в методе внешнего класса, где компилятор позаботится об этом автоматически.

Чтобы не спутать себя и других программистов с этой редко используемой функцией, вы всегда можете сделать внутренние классы статичными.

В случае, если требуется ссылка на внешний класс, вы можете передать ее явно в конструкторе.

Вы действительно можете сделать это, но вы должны объявить ClickEventкакstatic внутри Buttonи тогда у вас не должно возникнуть проблем с использованием синтаксиса:

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

Ваш код скомпилируется, если бы вы набрали

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

вместо

buttonClick(new Button.ClickEvent(button));

поскольку конструктор - это метод, и когда вы вызываете метод в Java, вы должны передать список аргументов, даже если он пуст.

Другие вопросы по тегам