这是官方文档对接口的介绍
What Is an Interface?
接口是类的抽象,确保类实现它提供接口,承诺提供给外界的所有服务。
在java中引入它主要是为了实现三个概念:
- 提供抽象
可以理解为接口是类的蓝图,如何提供服务的实现是对外部隐藏的,只有提供了什么服务是公开的。
- 实现多重继承
Java限制多重继承是为了避免两个父类有相同签名的方法引起的 钻石问题/菱形继承问题,编译器无法决定在这种情况下调用哪个方法。
Java通过接口解决,因为所有抽象方法都应该由实现它的具体类来实现。
如果接口的方法引起歧义(虽然java不支持类的多重继承,但支持实现多个接口,当一个类实现了接口B,C,而接口B和C都继承于接口A时,会出现类似的问题。),但可以决定调用接口方法(在文章后面讨论)
- 实现松耦合
由于接口可以用作类型,因此可以实现松散耦合,因此无需直接在依赖类内部实例化对象。用户可以决定需要哪种接口类型的实现。
接口的演变
-
在 JAVA 8
之前,接口只包含默认为 public
和 abstract
的抽象方法和默认为 public static final
的常量。
-
在 JAVA 8
之后接口可以有默认和静态方法,这些方法应该在它自己的接口中实现。默认情况下,两者都是公开的。
-
在 JAVA 9
之后允许私有方法和私有静态方法。
为什么是默认方法?
在开发中,如果我们想在接口中添加新的方法签名,所有已经实现这个接口的类都需要修改。
默认方法解决了这个问题,因为它们有实现和一些限制来避免菱形问题。需要这个默认方法的类可以直接使用它,也可以覆盖它。通过这个 JAVA 保持它的向后兼容性。
为什么定义私有方法?
增加代码的重用性并改进封装。它只能在默认情况下和接口内的其他私有方法中访问。在决定可访问性时,还应考虑静态和非静态上下文。
接口可以具有嵌套类型,例如类、枚举和接口。
接口不能有实例变量、构造函数、受保护的访问修饰符。
标记接口
标记接口是没有方法或常量的接口。它只是一个空的接口。它提供运行时对象的类型信息。它满足 instanceOf 方法。
函数式接口
函数式接口是只包含一个抽象方法的接口。它可以包含默认的静态和私有方法。它在 java 8
中被引入以支持 lambda
表达式,这是一个函数式编程概念。
在函数式接口之前,通常具体类必须实现接口中的所有抽象方法,即使它不需要它。现在因为函数式接口只有一个抽象方法,所以类只能实现需要的接口。
`@FunctionalInterface` 注解用于保证函数式接口只能有一个抽象方法。尽管此注释不是强制性的,但建议使用它以避免意外地将额外的抽象方法放入这些接口中。
`java.util.function` 包包含 `Java 8` 中的许多内置函数接口,它们主要与 `lambda` 表达式一起使用。
JAVA SE 9 之后的抽象类与接口
-
抽象类可以有抽象的方法,也可以有实现的(非抽象)方法。接口可以有抽象方法和默认方法。
-
抽象类可以有实例变量、静态变量和常量。默认情况下,接口只能具有公共静态const常量。
-
抽象类不支持多重继承。接口支持多重继承。
-
抽象类的成员可以拥有 public
protected
private
并且可以保留默认包级别访问权限。接口抽象方法和默认方法默认是公共的。私有和静态方法也是允许的。
-
抽象类可以扩展另一个java类并实现多个接口。接口只能扩展一个接口。
总结
-
Java 中的接口在每个版本中都不断发展以解决各种问题。接口提供了很好的抽象,支持多重继承并支持实现松耦合。
-
引入函数式接口以支持函数式编程概念。