Java-嵌套接口

偶尔善良 提交于 2020-01-23 21:22:39

Java-嵌套接口

1. 什么是嵌套接口

嵌套接口可以被称为 inner interface,也可以称为 nested class。

  • 接口可以嵌套在类或者其他接口中。

  • 当在类中嵌套接口时可以是 public、private 以及默认包访问权限。

  • 当在接口中嵌套接口时,其必须为 public(由于接口的性质,其默认也是public)。

为什么使用嵌套接口:

  • 当一个接口只会在另一个接口中使用时,这样设计符合逻辑;
  • 有利于封装(良好的框架不应该暴露给用户过多的实现细节,包括接口);
  • 嵌套接口更具可读性以及可维护性;

 在 Java 类库中一个典型的嵌套接口的例子是 java.util.Map 以及 Java.util.Map.Entryjava.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 内部接口。其父子关系如下图所示:

hierarchy

 虽然 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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!