我刚刚在我们的代码库中发现了一个静态嵌套接口。

class Foo {
    public static interface Bar {
        /* snip */
    }
    /* snip */
}

我以前从未见过这个。原来的开发人员已经找不到了。因此我不得不问SO:

静态接口背后的语义是什么?如果我移除这些静电,会发生什么变化?为什么会有人这么做?


当前回答

内部接口必须是静态的,才能被访问。该接口与类的实例无关,而是与类本身相关,因此可以通过Foo访问它。酒吧,像这样:

public class Baz implements Foo.Bar {
   ...
}

在大多数情况下,这与静态内部类没有什么不同。

其他回答

上面例子中的static关键字是多余的(嵌套的接口是自动“静态”的),可以删除而不影响语义;我建议将其删除。接口方法上的“public”和接口字段上的“public final”也是如此——修饰符是多余的,只会给源代码增加混乱。

不管怎样,开发人员只是声明了一个名为Foo.Bar的接口。除了不能访问Foo的代码将不能访问Foo之外,与外围类没有进一步的关联。酒吧。(从源代码-字节码或反射可以访问Foo。即使Foo是包私有的!)

如果您希望只从外部类使用嵌套接口,那么以这种方式创建嵌套接口是可以接受的,这样就不会创建新的顶级名称。例如:

public class Foo {
    public interface Bar {
        void callback();
    }
    public static void registerCallback(Bar bar) {...}
}
// ...elsewhere...
Foo.registerCallback(new Foo.Bar() {
    public void callback() {...}
});

The question has been answered, but one good reason to use a nested interface is if its function is directly related to the class it is in. A good example of this is a Listener. If you had a class Foo and you wanted other classes to be able to listen for events on it, you could declare an interface named FooListener, which is ok, but it would probably be more clear to declare a nested interface and have those other classes implement Foo.Listener (a nested class Foo.Event isn't bad along with this).

1998年,Philip Wadler提出了静态接口和非静态接口之间的区别。

在我看来,唯一的区别是 接口非静态是指它现在可以包含非静态的内部 类;所以这个改变不会使任何现有的Java无效 项目。

例如,他提出了“表达问题”的解决方案,即“你的语言能表达多少”的表达与“你试图用你的语言表达的术语”的表达之间的不匹配。

静态和非静态嵌套接口之间的区别可以在他的示例代码中看到:

// This code does NOT compile
class LangF<This extends LangF<This>> {
    interface Visitor<R> {
        public R forNum(int n);
    }

    interface Exp {
        // since Exp is non-static, it can refer to the type bound to This
        public <R> R visit(This.Visitor<R> v);
    }
}

他的建议从未出现在Java 1.5.0中。因此,所有其他答案都是正确的:静态和非静态嵌套接口没有区别。

如果你将类Foo改为接口Foo,上面例子中的“public”关键字也将是多余的,因为

在另一个接口中定义的接口将隐式公开 静态的。

成员接口是隐式静态的。可以在不改变代码语义的情况下删除示例中的静态修饰符。请参见Java语言规范8.5.1。静态成员类型声明