我刚刚在代码库中找到了一个静态嵌套接口.
class Foo { public static interface Bar { /* snip */ } /* snip */ }
我以前从未见过这个.最初的开发者是遥不可及的.因此我不得不问:
静态接口背后的语义是什么?如果我删除了会有什么变化static
?为什么有人会这样做?
上例中的static关键字是冗余的(嵌套接口自动为"静态"),可以删除而不影响语义; 我建议将其删除.接口方法中的"public"和接口字段上的"public final"也是如此 - 修饰符是冗余的,只是为源代码添加了混乱.
无论哪种方式,开发人员只是声明一个名为Foo.Bar的接口.除了无法访问Foo的代码也无法访问Foo.Bar之外,没有与封闭类的进一步关联.(从源代码 - 字节码或反射可以访问Foo.Bar,即使Foo是包私有的!)
如果您希望仅从外部类中使用嵌套接口,则以这种方式创建嵌套接口是可接受的样式,这样您就不会创建新的顶级名称.例如:
public class Foo { public interface Bar { void callback(); } public static void registerCallback(Bar bar) {...} } // ...elsewhere... Foo.registerCallback(new Foo.Bar() { public void callback() {...} });
这个问题已得到解答,但使用嵌套接口的一个很好的理由是它的函数与它所在的类直接相关.一个很好的例子是a Listener
.如果你有一个类,Foo
并且你希望其他类能够监听它上面的事件,你可以声明一个名为的接口FooListener
,这是可以的,但是声明一个嵌套接口并实现其他类可能会更清楚Foo.Listener
(嵌套类Foo.Event
也不错()).
成员接口是隐式静态的.可以删除示例中的static修饰符,而无需更改代码的语义.另请参阅Java语言规范8.5.1.静态成员类型声明
内部接口必须是静态的才能被访问.接口不与类的实例相关联,但与类本身相关联,因此可以使用它来访问Foo.Bar
,如下所示:
public class Baz implements Foo.Bar { ... }
在大多数情况下,这与静态内部类没有什么不同.
Jesse的答案很接近,但我认为有一个更好的代码来证明为什么内部接口可能有用.在阅读之前,请查看下面的代码.你能找到为什么内部接口有用吗?答案是类DoSomethingAlready可以用任何实现A和C的类实例化; 不仅仅是具体的动物园类.当然,即使AC不是内在的,也可以实现这一点,但想象一下连接更长的名称(不仅仅是A和C),并且为其他组合(比如A和B,C和B等)做这个并且你很容易看看事情如何失控.更不用说审查源代码树的人将被仅在一个类中有意义的接口所淹没.总而言之,内部接口允许构建自定义类型并改进其封装.
class ConcreteA implements A { : } class ConcreteB implements B { : } class ConcreteC implements C { : } class Zoo implements A, C { : } class DoSomethingAlready { interface AC extends A, C { } private final AC ac; DoSomethingAlready(AC ac) { this.ac = ac; } }