4

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 抱怨“成员接口 Bar 只能在顶级类或接口中定义”。是否有一个原因?还是我错过了我犯的错误?

4

4 回答 4

5

Java 语言规范并没有告诉你为什么它是这样设计的,但它确实描述了什么是允许的,什么是不允许的。

方法具有以下形式

MethodBody:
    Block 
    ;

Block在哪里

Block:
    { BlockStatementsopt }

BlockStatements:
    BlockStatement
    BlockStatements BlockStatement

BlockStatement:
    LocalVariableDeclarationStatement
    ClassDeclaration
    Statement

所以类声明是允许的,但接口是不允许的。


我们可以争辩说,从调用者的角度来看,拥有一个本地接口并不是很有用。它没有任何目的。接口旨在描述行为,但由于接口是本地的,因此调用者无法使用它。您也可以在类中定义和实现行为。

于 2014-02-02T21:23:18.310 回答
5

JLS 中根本没有对它的定义。它只是不存在。

至于弱的原因,根据JLS 14.3

所有本地类都是内部类(§8.1.3)。

接口不能是内部的(JLS 8.1.3):

成员接口(第 8.5 节)是隐式静态的,因此它们永远不会被视为内部类。

所以我们不能有一个本地接口。

这是,我猜,除了@SotiriosDelimanolis 发现 InterfaceDeclaration 不是 BlockStatement。

于 2014-02-02T21:48:00.207 回答
2

本地接口(和枚举)已与记录类功能一起引入:

不幸的是,此功能在文档中有点模糊 - 但它有效。

两个版本都允许编写如下代码:

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());
    }

}
于 2021-02-22T17:34:16.827 回答
0

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
于 2021-11-02T09:04:27.803 回答