Java-嵌套接口
1. 什么是嵌套接口
嵌套接口可以被称为 inner interface,也可以称为 nested class。
-
接口可以嵌套在类或者其他接口中。
-
当在类中嵌套接口时可以是 public、private 以及默认包访问权限。
-
当在接口中嵌套接口时,其必须为 public(由于接口的性质,其默认也是public)。
为什么使用嵌套接口:
- 当一个接口只会在另一个接口中使用时,这样设计符合逻辑;
- 有利于封装(良好的框架不应该暴露给用户过多的实现细节,包括接口);
- 嵌套接口更具可读性以及可维护性;
在 Java 类库中一个典型的嵌套接口的例子是 java.util.Map 以及 Java.util.Map.Entry。java.util.Map在这里也起到了命名空间的作用。关于命名空间详细点说就是如果这个 Entry 不做为 Map 接口的一个内部接口,那么为了说明这个接口是用于 Map 的实现的一部分,就应该取名为 MapEntry。那么对于企业级别的框架设计而言,这将会有非常多的 MapEntry。一般用户却不需要实现这些接口,但是这些接口却和 Map 这些可能被用户实现的接口在同一级别上,不利于阅读。
Entry类不属于全局作用域,这也就意味着很多是 Entry 类型的 Entry 对象并不是java.util.Map类型。这里的Java.util.Map.Entry可以认为是 Map 类的 Entry。
2. 嵌套接口一般使用逻辑
在学习嵌套接口之前,可以参照嵌套类。
嵌套类可以视为在外部类中声明的常规方法。 由于可以将方法声明为静态或非静态,因此类似的嵌套类可以是静态和非静态的。 静态类就像静态方法一样,它只能通过对象访问外部类成员(非静态)。 非静态类可以访问外部类的任何成员。
示例代码:
public class OuterClass {
private int x;
static class StaticInnerClass{
void innerMethod(){
//虽然没有使用 static 修饰,但是如同静态方法一样可以通过对象访问外部类的域
System.out.println(new OuterClass().x);
}
}
class NonStaticInnerClass{
void InnerMethod(){
//也没有使用 static 修饰方法,可以像非静态方法那样,直接访问外部类的域
System.out.println(x);
}
}
}
作为对比,类内一般调用域的静态和非静态方法:
public class NormalClass {
private int x;
static void staticMethod(){
System.out.println(new NormalClass().x);
}
void noStaticMethod(){
System.out.println(x);
}
}
因为接口是无法实例化的,所以内部接口除非是 static 才是有意义的。因此内部接口默认就是 static 修饰的,人为添加上 static 修饰是冗余的。
内部接口不仅仅是供其定义处的外接口创建内部类使用,其还供外部接口的实现类的内部类实现,否则,简单地在内部接口中创建一个内部类就满足了需求。
关于嵌套类使用逻辑的典型例子是: java.util.HashMap 实现了 java.util.Map接口,而静态内部类java.util.HashMap.Node实现了 java.util.Map.Entry 内部接口。其父子关系如下图所示:

虽然 Java 中的外部接口不都是 public,可以为包访问权限,但是嵌套接口必须声明为 public。我们可以越过实现外部接口,直接实现一个内部接口,并实现多态(虽然一般情况下我们不需要这样做),如下面代码所示:
public interface Test{
void Outtermethod();
interface innerInterface{
void Innermethod();
}
}
class TestClass implements Test.innerInterface{
@Override
public void Innermethod() {
System.out.println("xxxx");
}
public static void main(String[] args) {
Test.innerInterface instance = new TestClass2();
instance.Innermethod();
}
}
//控制台输出:xxxx
这里没有外部类实现外部接口,只有非内部类实现一个内部接口,一定程度上破坏了良好的内外逻辑–内部作为外部的组件,提供功能。
3. 嵌套接口为何默认为 static
在 Java 中,当 static 关键字用于修饰域以及方法时,其主要用于强调与特定的实例无关的特性。但是 static 用于修饰接口以及类时,其含义还是如此吗?为了说明这个问题,首先我们先参照内部类的设计逻辑:
首先,内部类外加一个 static 并不是为了说明这个类中的所有方法都是静态方法,static 类中可以同时存在静态方法和非静态方法。
其次,关于内部类的访问权限有:public、private、protected 以及包访问权限。
非静态内部类中不能存在静态方法。
所以 static 关键字用于方法、域与作用于接口和类有着不同的含义。当 static 作用于内部类时,用于强调内部类的实现细节相对于外部类独立,比如说想要创建嵌套类对象并不需要外部类的对象。
非静态内部类创建实例的代码:
public class Test2 {
class InnerClass {
}
public static void main(String[] args) {
Test2 test = new Test2();
InnerClass innerClass = test.new InnerClass();
}
}
静态内部类创建实例的代码:
public class Test2 {
static class InnerClass {
}
public static void main(String[] args) {
InnerClass innerClass = new InnerClass();
}
}
而嵌套接口默认使用 static 关键字的用意和内部类是类似的。接口本身就是抽象的集合,也不依赖于外部接口也不与特定类相关,任何类只要提供了指定的相关方法,那么该类就算实现了这个接口(接口设计者可不知道今后会被谁实现,只是规定了实现着要提供的方法)。 static 就是用于强调接口的这个特点。
可以认为嵌套接口和外部接口区别并不大,嵌套接口主要提供了一层内外的逻辑关系:内作为外的一共功能组成,且并不希望直接暴露给外部。但是这种封装是不彻底的,因为嵌套接口默认且只能使用 public 修饰。
类似于静态内部类,我们可以跳过外部接口,也可以直接就可以创建内部接口的声明的对象。一个典型的例子就是 Android 开发中设计按钮的响应事件所用到的:
Button btn = (Button ) findViewById(R.id.btnStart);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//Do something...
}
});
其中 OnClickLisetener()就是一个嵌套接口,具体地为:android.view.View.OnClickListener。进一步说,此方法参数虽然为一个嵌套接口,但是其用法和一般接口没有区别,就是凭借多态,只编写关于基类的方法罢了。内部接口的用意是 OnClickListener 接口作为一个事件监听器,提供给 View 接口就足够了,并不需要暴露给其他类的相关方法。static 关键字也不是强调静态性,而是强调无关性,说明这个接口并不依赖外部类 View。
在 JavaSE5 接口中没有静态方法,所以即使嵌套接口默认由 static 修饰,嵌套接口内部也不能有静态方法。
在 JDK1.8 版本中,添加了接口的静态方法,但是不存在多态。并且强制规定接口的静态方法必须由接口本身直接调用,不能通过对象调用。
参考网址:
- https://www.zhihu.com/question/28197253
- https://stackoverflow.com/questions/27096561/why-are-interfaces-static
- https://stackoverflow.com/questions/70324/java-inner-class-and-static-nested-class
- https://www.javaworld.com.tw/jute/post/view?bid=29&id=308251
来源:CSDN
作者:渔夫Fisherman
链接:https://blog.csdn.net/li_xunhuan/article/details/104077592