Java基础 | 接口(Interface)

1.概念

    在Java程序设计语言中,接口不是类,而是对希望符合这个接口的类的一组需求(类似于抽象类,皆为抽象内容,却又区别于抽象类)。由于Java不支持多重继承特性,每个类只能扩展一个类,但可以实现多个接口。实际上,接口可以提供多重继承的大多数好处,同时还能避免多重继承的复杂性和低效性。

2.属性

  • 接口不是类,具体来说,不能使用 new 运算符实例化
    InterfaceName aInterface = new InterfaceName() // Error

  • 一个接口。尽管不能构造接口的对象,却能声明接口的变量。接口变量必须引用实现implements了该接口的类对象。
    InterfaceName aClass = new ClassName() // class ClassName implements InterfaceName

  • 如同使用 instanceof 检查一个对象是否属于某个特定类一样,也可以使用 instanceof 检查一个对象是否实现类某个特定的接口。
    anObject instanceof InterfaceName

  • 与建立类的继承层次一样,也可以扩展extends接口层次。允许存在多条接口链,从通用性较高的接口扩展到专用性较高的接口。
    interface InterfaceName1 extends InterfaceName {…}
    interface InterfaceName2 extends InterfaceName {…}
    interface InterfaceName11 extends InterfaceName1 {…}
    … …

  • 虽然在接口中不能包含实例字段,但是可以包含常量。与接口中的方法自动被设置为public abstract一样,接口中的字段总是public static final。(Java语言规范建议不要提供多余的关键字,即无需修饰)

  • 静态方法:在Java 8中,允许在接口中定义静态static方法。理论上讲,没有任何理由认为这是不合法的,只是这有违于将接口作为抽象规范的初衷。目前为止,通常的做法都是将静态方法放在伴随类中。在标准库中,你会看到成对出现的接口和实用工具类, 如Collection/Collections 或Path/Paths。

  • 私有方法:在Java 9中,接口中的方法可以是private。private方法可以是静态方法或实例方法。由于私有方法只能在接口本身的方法中使用,所以它们的用法很有限,只能作为接口中其他方法的辅助方法。

  • 默认方法:在Java 8之前,接口中的方法都是抽象的,不允许有方法体。在此之后可以为接口方法提供一个默认实现,必须用default修饰符标记这样一个方法。默认方法可以调用其他方法。

    • 解决默认方法冲突问题:
    1. 超类优先。如果超类提供了一个具体方法,同名而且有相同参数类型的默认方法会被忽略。
    2. 接口冲突。如果一个接口提供了一个默认方法,另一个接口提供了一个同名而且参数类型相同的方法(不管是否为默认方法),必须覆盖这个方法来解决冲突。
    • 情形一:会继承接口中多个签名相同、实现不同的默认方法。类必须重写该方法,以解决二义性问题。
      class ClassName implements InterfaceName1, InterfaceName2 {
          @Override
          public String getInterfaceName() { return " InterfaceName1 + InterfaceName2"; }
          …
      }
      interface InterfaceName1 {
          default String getInterfaceName() { return " InterfaceName1"; }
          …
      }
      interface InterfaceName2 {
          default String getInterfaceName() { return " InterfaceName2"; }
          …
      }
    • 情形二:会继承接口中多个签名相同的默认方法与抽象方法。类必须重写该方法,以解决二义性问题。
      class ClassName implements InterfaceName1, InterfaceName2 {
          @Override
          public String getInterfaceName() { return " InterfaceName1 + InterfaceName2"; }
          …
      }
      interface InterfaceName1 {
          default String getInterfaceName() { return " InterfaceName1";}
          …
      }
      interface InterfaceName2 {
          String getInterfaceName();
          …
      }
    • 情况三:存在多个签名相同的(非默认)方法(与Java 8之前情形一样,不存在冲突)。两种选择:①类实现该方法;②不实现该方法,作为抽象类。
      ①class ClassName implements InterfaceName1, InterfaceName2 {
          @Override
          public String getInterfaceName() { return " InterfaceName1 + InterfaceName2"; }
          …
      }

      ②abstract class ClassName implements InterfaceName1, InterfaceName2 {
          abstract public String getInterfaceName() // 可有可无
          …
      }
      interface InterfaceName1 {
          String getInterfaceName();
          …
      }
      interface InterfaceName2 {
          String getInterfaceName();
          …
      }
    • 情况四:扩展了超类,同时实现了接口,会继承多个签名相同的方法。此时,子类只会考虑超类的具体方法,接口的默认方法都会被忽略。
      class ClassName extends SuperClassName implements InterfaceName {
          //getInterfaceName()方法不存在问题,只会继承超类该方法。
          …
      }
      class SuperClassName {
          public String getInterfaceName() { return " null"; }
          …
      }
      interface InterfaceName {
          default String getInterfaceName() { return " InterfaceName";}
          …
      }
上一篇:深度理解抽象类和接口


下一篇:typesscript基础到vue项目中的使用