为什么在Java中使用静态嵌套接口?

时间:2020-03-05 18:55:45  来源:igfitidea点击:

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

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

我以前从未见过。原始开发人员遥不可及。因此,我不得不问:

静态接口背后的语义是什么?如果我删除了" static",会发生什么变化?为什么有人会这样做?

解决方案

回答

内部接口必须是静态的才能被访问。该接口与该类的实例无关,但与该类本身相关联,因此可以通过Foo.Bar进行访问,如下所示:

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

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

回答

要直接回答问题,请查看Map.Entry。

地图条目

这也可能有用

静态嵌套的Inerfaces博客条目

回答

通常,我看到静态内部类。静态内部类不能引用包含类,而非静态类可以。除非我们遇到一些程序包冲突(与Foo相同的程序包中已经有一个名为Bar的接口),否则我认为我将其设为自己的文件。强制执行Foo和Bar之间的逻辑连接也可能是一个设计决策。也许作者打算将Bar只与Foo一起使用(尽管静态内部接口不会强制执行此操作,而只是逻辑连接)

回答

静态意味着包(项目)的任何类部分都可以访问它而无需使用指针。根据情况,这可能有用或者受阻。

Math类是"静态"方法有用的完美示例。 Math中的所有方法都是静态的。这意味着我们不必费力地创建新实例,声明变量并将它们存储在更多变量中,我们只需输入数据即可获得结果。

静态并不总是那么有用。例如,如果要进行案例比较,则可能需要以几种不同的方式存储数据。我们不能创建三个具有相同签名的静态方法。我们需要3个不同的实例(非静态),然后可以进行比较,如果是静态的,则数据不会随输入而改变。

静态方法非常适合一次性收益和快速计算或者容易获得的数据。

回答

在Java中,静态接口/类允许接口/类的使用像顶级类一样,也就是说,它可以由其他类声明。因此,我们可以执行以下操作:

class Bob
{
  void FuncA ()
  {
    Foo.Bar foobar;
  }
}

没有静态,以上内容将无法编译。这样做的好处是,我们不需要新的源文件即可声明接口。由于必须编写Foo.Bar,因此它还可视化地将Bar接口与Foo类关联,并暗示Foo类对Foo.Bar实例进行了某些操作。

Java中的类类型的描述。

回答

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

无论哪种方式,开发人员都只是声明一个名为Foo.Bar的接口。与封闭类没有进一步的关联,除了无法访问Foo的代码也将无法访问Foo.Bar。 (即使Foo是程序包私有的,也可以从源代码通过字节码或者反射方式访问Foo.Bar!)

如果希望只在外部类中使用嵌套接口,则可以通过这种方式创建嵌套接口,这样我们就不必创建新的顶级名称。例如:

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

回答

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

回答

这个问题已经得到了回答,但是使用嵌套接口的一个很好的理由是它的功能是否与其所在的类直接相关。一个很好的例子是Listener。如果我们有一个类" Foo",并且希望其他类能够侦听其上的事件,则可以声明一个名为" FooListener"的接口,可以,但是声明嵌套的接口和让那些其他类实现Foo.Listener(嵌套类Foo.Event也不错)。