Странный синтаксис для создания экземпляра внутреннего класса
Я не предполагал, что на этом этапе я больше столкнулся с радикально новым синтаксисом в 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
являются не абстрактными общедоступными классами.
Ответы
Ответ 1
Внутренние классы (например, 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 спецификации.
Ответ 2
Button.ClickEvent - нестатический внутренний класс, поэтому экземпляр этого класса может существовать только в экземпляре Button.
В вашем втором примере кода у вас есть экземпляр Button, и вы создаете экземпляр ClickEvent, заключенный в этот экземпляр Button...
Ответ 3
Нестатический внутренний класс в Java содержит скрытую ссылку, указывающую на экземпляр внешнего класса, в котором он объявлен. Таким образом, сообщение об ошибке, которое вы изначально рассказываете, говорит вам, что вы не можете создать новый экземпляр внутреннего класса без указания экземпляра внешнего класса для присоединения к нему.
Возможно, причина, по которой вы не видели этот синтаксис раньше, заключается в том, что внутренние классы часто выделяются в методе внешнего класса, где компилятор автоматически выполняет это.
Ответ 4
Чтобы не запутать себя и других программистов с помощью этой редко используемой функции, вы всегда можете сделать внутренние классы статическими.
Если требуется ссылка на внешний класс, вы можете передать его явно в конструкторе.
Ответ 5
Вы действительно можете сделать это, но вам нужно объявить ClickEvent
как static
внутри 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) {
}
}
Ответ 6
Ваш код будет скомпилирован, если бы вы набрали
buttonClick(new Button().ClickEvent(button));
вместо
buttonClick(new Button.ClickEvent(button));
как конструктор - это метод, и когда вы вызываете метод в Java, вы должны передать список аргументов, даже когда он пуст.