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

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

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

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


当前回答

在Java中,静态接口/类允许接口/类像顶级类一样使用,也就是说,它可以由其他类声明。所以,你可以:

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

如果没有静态,上述代码将无法编译。这样做的好处是,您不需要一个新的源文件来声明接口。它还可视化地将接口Bar与类Foo关联起来,因为你必须编写Foo。Bar并暗示Foo类对Foo.Bar的实例做一些事情。

Java中类类型的描述。

其他回答

Typically I see static inner classes. Static inner classes cannot reference the containing classes wherease non-static classes can. Unless you're running into some package collisions (there already is an interface called Bar in the same package as Foo) I think I'd make it it's own file. It could also be a design decision to enforce the logical connection between Foo and Bar. Perhaps the author intended Bar to only be used with Foo (though a static inner interface won't enforce this, just a logical connection)

在Java中,静态接口/类允许接口/类像顶级类一样使用,也就是说,它可以由其他类声明。所以,你可以:

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

如果没有静态,上述代码将无法编译。这样做的好处是,您不需要一个新的源文件来声明接口。它还可视化地将接口Bar与类Foo关联起来,因为你必须编写Foo。Bar并暗示Foo类对Foo.Bar的实例做一些事情。

Java中类类型的描述。

内部接口必须是静态的,才能被访问。该接口与类的实例无关,而是与类本身相关,因此可以通过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() {...}
});

Jesse's answer is close, but I think that there is a better code to demonstrate why an inner interface may be useful. Look at the code below before you read on. Can you find why the inner interface is useful? The answer is that class DoSomethingAlready can be instantiated with any class that implements A and C; not just the concrete class Zoo. Of course, this can be achieved even if AC is not inner, but imagine concatenating longer names (not just A and C), and doing this for other combinations (say, A and B, C and B, etc.) and you easily see how things go out of control. Not to mention that people reviewing your source tree will be overwhelmed by interfaces that are meaningful only in one class.So to summarize, an inner interface enables the construction of custom types and improves their encapsulation.

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