Странный синтаксис для создания экземпляра внутреннего класса - PullRequest
41 голосов
/ 11 марта 2009

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

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

Ответы [ 6 ]

69 голосов
/ 11 марта 2009

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

9 голосов
/ 11 марта 2009

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

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

8 голосов
/ 11 марта 2009

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

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

3 голосов
/ 11 марта 2009

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

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

1 голос
/ 15 февраля 2016

На самом деле вы можете сделать это , но вы должны объявить 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) {
    }
}
0 голосов
/ 11 марта 2009

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

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

вместо

buttonClick(new Button.ClickEvent(button));

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...