Есть ли такая вещь, как "локальный интерфейс" в Java?

Java позволяет мне определять локальные абстрактные классы, как в этом примере:

public class Foo {

    public void foo() {
        abstract class Bar {          // Bar is a local class in foo() ...
            abstract void bar();
        }

        new Bar() {                   // ... and can be anonymously instantiated
            void bar() {
                System.out.println("Bar!");
            }
        }.bar();
    }
}

По какой-то причине, когда я пытаюсь определить "локальный интерфейс" вместо локального класса, вот так:

public class Foo {

    public void foo() {
        interface Bar {           // Bar was supposed to be a local interface...
            void bar();
        }

        new Bar() {               // ... to be anonymously instantiated
            void bar() {
                System.out.println("Bar!");
            }
        }.bar();
    }
}

Java жалуется, что "Панель интерфейса члена может быть определена только внутри класса или интерфейса верхнего уровня". Для этого есть причина? Или я пропустил ошибку, которую сделал?

4 ответа

Решение

Там просто нет определения для этого в JLS. Это просто не существует.

Что касается слабой причины, в соответствии с JLS 14.3:

Все локальные классы являются внутренними классами (§8.1.3).

Интерфейс не может быть внутренним ( JLS 8.1.3):

Интерфейсы-члены (§8.5) неявно статичны, поэтому они никогда не считаются внутренними классами.

Поэтому у нас не может быть локального интерфейса.

Это, я думаю, в дополнение к тому, что @SotiriosDelimanolis обнаружил, что InterfaceDeclaration не является BlockStatement.

Спецификация языка Java не говорит вам, почему она была разработана так, как она была, но она описывает, что есть, а что нет.

Тело метода имеет следующую форму

MethodBody:
    Block 
    ;

где Block является

Block:
    { BlockStatementsopt }

BlockStatements:
    BlockStatement
    BlockStatements BlockStatement

BlockStatement:
    LocalVariableDeclarationStatement
    ClassDeclaration
    Statement

Поэтому объявление класса разрешено, а интерфейс - нет.


Мы можем утверждать, что наличие локального интерфейса не очень полезно с точки зрения вызывающего. Это не служит какой-либо цели. Интерфейс предназначен для описания поведения, но поскольку интерфейс будет локальным, ни один вызывающий не сможет его использовать. Вы также можете определить и реализовать поведение в классе.

Локальные интерфейсы (и перечисления) были введены вместе с функцией классов записей:

К сожалению, эта функция немного скрыта в документации, но она работает.

Обе версии позволяют писать код, как показано ниже:

      public class Main {

    public int foo() {

        interface Experimentable {
            int bar();
        }

        Experimentable e = new Experimentable() {
            @Override
            public int bar() {
                return 0;
            }
        };

        return e.bar();
    }

    public static void main(String[] args) {
        System.out.println(new Main().foo());
    }

}

Java теперь (начиная с 16) поддерживает локальный интерфейс .

Локальный интерфейс - это вложенный интерфейс (§9 (Интерфейсы)), объявление которого немедленно содержится в блоке.

И ваш (немного поправил, потому что bar внедрение должно быть общедоступным) код компилируется нормально.

      public class Foo {

    public void foo() {
        interface Bar {           // Bar was supposed to be a local interface...
            void bar();
        }

        new Bar() {               // ... to be anonymously instantiated
            public void bar() {
                System.out.println("Bar!");
            }
        }.bar();
    }
}

Компиляция:

      ~/tmp $ /usr/local/opt/java/bin/javac -version
javac 17
~/tmp $ /usr/local/opt/java/bin/javac Foo.java
Другие вопросы по тегам