it-swarm.cn

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

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

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

我以前从未见过这个。最初的开发者是遥不可及的。因此我不得不问:

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

230
Mo.

上例中的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() {...}
});
290
Jesse Glick

这个问题已得到解答,但是使用嵌套接口的一个很好的理由是它的函数与它所在的类直接相关。一个很好的例子是Listener。如果你有一个类Foo并且你希望其他类能够监听它上面的事件,你可以声明一个名为FooListener的接口,这没关系,但是声明一个嵌套接口并拥有其他类可能会更清楚实现Foo.Listener(嵌套类Foo.Event也不错)。

71
ColinD

成员接口是隐式静态的。可以删除示例中的static修饰符,而无需更改代码的语义。另请参阅Java语言规范 8.5.1。静态成员类型声明

13
Bas Leijdekkers

内部接口必须是静态的才能被访问。接口不与类的实例相关联,但与类本身相关联,因此可以使用Foo.Bar访问它,如下所示:

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

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

9
Clinton N. Dreisbach

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;
  }
}
6
user1982892

要非常直接地回答您的问题,请查看Map.Entry。

Map.Entry

这也许有用

Static Nested Inerfaces博客文章

3
Henry B

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中得到过。因此,所有其他答案都是正确的:静态和非静态嵌套接口没有区别。

0
Pindatjuh

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

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

0
Danylo Volokh

通常我会看到静态内部类。静态内部类不能引用非静态类所在的包含类。除非你遇到一些包冲突(在与Foo相同的包中已经有一个名为Bar的接口),我想我会把它变成自己的文件。它也可能是强制Foo和Bar之间逻辑连接的设计决策。也许作者希望Bar只与Foo一起使用(虽然静态内部接口不会强制执行此操作,只是逻辑连接)

0
basszero