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