为什么在Java中使用静态嵌套接口?
我刚刚在我们的代码库中find了一个静态嵌套的接口。
class Foo { public static interface Bar { /* snip */ } /* snip */ }
我从来没有见过这个。 原来的开发人员遥不可及。 所以我不得不问:
什么是静态接口背后的语义? 如果我删除static
会有什么变化? 为什么有人会这样做?
上面例子中的static关键字是多余的(一个嵌套的接口是自动的“静态的”),可以被删除而不影响语义; 我会build议它被删除。 接口方法中的“public”和接口字段中的“public final”也是一样 – 修饰符是多余的,只是给源代码添加混乱。
无论哪种方式,开发人员只是简单地声明一个名为Foo.Bar的接口。 除了不能访问Foo的代码也不能访问Foo.Bar之外,与封闭类没有进一步的关联。 (从源代码 – 字节码或reflection可以访问Foo.Bar即使Foo是封装私有!)
如果您只希望从外部类中使用嵌套接口,那么创build一个嵌套接口是可接受的样式,这样您就不会创build新的顶级名称。 例如:
public class Foo { public interface Bar { void callback(); } public static void registerCallback(Bar bar) {...} } // ...elsewhere... Foo.registerCallback(new Foo.Bar() { public void callback() {...} });
这个问题已经得到解答,但是使用嵌套接口的一个很好的理由是它的函数直接与它所在的类相关。一个很好的例子是一个Listener
。 如果你有一个Foo
类,并且你希望其他的类能够监听它的事件,你可以声明一个名为FooListener
的接口,这个接口是可以的,但是声明一个嵌套的接口并且使用其他类实现Foo.Listener
(嵌套类Foo.Event
并不坏)。
成员接口是隐式静态的。 您的示例中的静态修饰符可以在不更改代码的语义的情况下被删除。 另请参阅Java语言规范8.5.1。 静态成员types声明
内部接口必须是静态的才能被访问。 该接口不与类的实例相关联,而是与类本身关联,因此可以使用Foo.Bar
访问Foo.Bar
,如下所示:
public class Baz implements Foo.Bar { ... }
在大多数情况下,这与静态的内部类没有什么不同。
杰西的答案是接近的,但我认为有一个更好的代码来演示为什么内部接口可能是有用的。 在阅读之前,先看下面的代码。 你能find为什么内部接口是有用的吗? 答案是类DoSomethingAlready可以用实现A和C的任何类实例化; 不只是具体的类动物园。 当然,即使AC不是内在的,也可以实现,但是想象连接更长的名字(不仅仅是A和C),并且为其他组合(比如A和B,C和B等)看看事情如何失控。 更不用说审查你的源代码树的人会被仅仅在一个类中有意义的接口所淹没。所以总而言之, 一个内部接口能够构build自定义types并改进它们的封装 。
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; } }
要直接回答你的问题,看看Map.Entry。
Map.Entry的
这也许是有用的
静态嵌套Inerfaces博客条目
如果您将Foo类更改为Foo界面,则上面示例中的“public”关键字也将是多余的,因为
在另一个接口内部定义的接口将隐含的公共静态。
通常我会看到静态的内部类。 静态内部类不能引用非静态类可以包含的类。 除非你碰到一些包冲突(在Foo的同一个包里已经有一个名为Bar的接口),我想我会把它做成自己的文件。 这也可能是一个强制Foo和Bar之间逻辑连接的devise决定。 也许作者希望Bar只能和Foo一起使用(尽pipe静态的内部接口不会强制执行,只是一个逻辑连接)
1998年,Philip Wadler提出了静态接口和非静态接口的区别。
据我所知,使接口非静态的唯一区别是它现在可以包含非静态的内部类; 所以更改不会使任何现有的Java程序无效。
例如,他提出了一个expression问题的解决scheme,一方面expression为“你的语言能expression多less”,另一方面expression为“你用你的语言expression的术语” 。
他的示例代码中可以看到静态和非静态嵌套接口之间差异的示例 :
// 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); } }
他的build议从来没有在Java 1.5.0中提出过。 因此,所有其他答案都是正确的:静态和非静态嵌套接口没有区别。
在Java中,静态接口/类允许接口/类像顶级类一样使用,也就是说,它可以由其他类声明。 所以,你可以这样做:
class Bob { void FuncA () { Foo.Bar foobar; } }
如果没有静态,上面的代码将无法编译。 这样做的好处是你不需要一个新的源文件来声明接口。 它也可视化地将接口Bar与类Foo联系起来,因为你必须编写Foo.Bar,并暗示Foo类与Foo.Bar的实例做了一些事情。
Java中的类types的描述 。
静态意味着包(项目)的任何类部分都可以在不使用指针的情况下访问它。 这可以是有用的或阻碍取决于情况。
math类是“静态”方法有用的完美例子。 math中的所有方法都是静态的。 这意味着您不必走出困境,创build新实例,声明variables并将其存储在更多variables中,只需input数据并获得结果即可。
静态并不总是那么有用。 如果你正在做案例比较,你可能想以几种不同的方式存储数据。 您不能创build三个具有相同签名的静态方法。 你需要3个不同的实例,非静态的,然后你可以和比较,如果它是静态的,数据不会随着input而改变。
静态方法适用于一次性返回和快速计算,或者获得简单的数据。