什么是接口

接口是一种规范,符合这个接口的类的一组需求。

在 Java 中使用 interface 关键字定义一个接口。

  1. public interface Ineter {
  2. void method();
  3. ....
  4. }

在 Java 中接口是一个类似于类的引用类型,它只能包含常量、方法签名、默认方法和嵌套类型。方法体仅适用于默认方法和静态方法。接口不能实例化,只能通过类 implemented 或通过其他接口 extended。

接口可以包含什么

三个 JDK 版本的接口设计功能对比。

Java 7 Java 8 Java 9
常量 常量 常量
抽象方法 抽象方法 抽象方法
默认方法 默认方法
公共静态方法 公共静态方法
私有方法(非私有静态方法)
私有静态方法

抽象方法

接口可以包含抽象方法,这是最基本的。因为接口定义的所有方法默认都是 public static 的,所以可以省略这些修饰符。

  1. public interface Inter {
  2. void abstractMenthod1();
  3. String abstractMethod2();
  4. ....
  5. }

常量

接口可以包含常量,所有常量值默认都是 public static final ,所以可以省略这些修饰符。

  1. public interface Inter {
  2. int a = 1;
  3. public static final String s = "test";
  4. ...
  5. }

默认方法

使用默认方法是为了方便拓展已有的接口,如果没有默认方法,加入给 JDK 中的某个接口添加一个新的抽象方法,那么所有实现了该接口的类都得修改,影响非常大。

使用 default 关键字定义,默认方法是默认都是 public(也只能是 public) ,包含方法体。

  1. public interface Inter {
  2. default String defaultMethod1() {
  3. return "this is defaultMethod1";
  4. }
  5. default public String defaultMethod2() {
  6. return "this is defaultMethod2";
  7. }
  8. ...
  9. }

静态方法

接口的静态方法可以是公共的(public)和私有的(private)默认是 public,其中私有静态方法是 Java 9 新增的特性,静态方法是属于接口的。私有静态方法只能被接口中的默认方法、其他的私有静态方法、公共静态方法、私有方法(非私有静态方法)访问。

  1. interface Inter {
  2. public static void publicStaticMethod() {
  3. System.out.println("this is publicStaticMethod");
  4. }
  5. public static void accessPrivateStaticMethodByPubicStaticMethod() {
  6. privateStaticMethod();
  7. }
  8. private static void privateStaticMethod() {
  9. System.out.println("this is privateStaticMethod");
  10. }
  11. private void accessPrivateStaticMethodByPrivateMethod() {
  12. privateStaticMethod();
  13. }
  14. default void accessStaticMethod() {
  15. privateStaticMethod();
  16. }
  17. }

私有方法(非私有静态方法)

这是 Java 9 新增的特性,用于解决多个默认方法之间重复代码问题。私有方法必须有方法体。

  1. interface Inter {
  2. default void defaultMethod1() {
  3. commonCode();
  4. System.out.println("this is defaultMethod1.");
  5. }
  6. default void defaultMethod2() {
  7. commonCode();
  8. System.out.println("this is defaultMethod2.");
  9. }
  10. private void commonCode() {
  11. System.out.println("this is commonCode.");
  12. }
  13. }

嵌套类型

接口可以嵌套在另外一个接口里面,类也可以嵌套在接口里面。(了解即可,这个特性没有人使用的。。。)

  1. interface Inter {
  2. default void defaultMethod() {
  3. System.out.println("defaultMethod");
  4. }
  5. interface nestedInter {
  6. }
  7. class nestedClass {
  8. }
  9. }

接口的实现

一个类可以实现一个或多个接口,使用关键字 implements 定义。

  1. public class Test implements ParentInter1, ParentInter2 {
  2. @Override
  3. public void ParentAbstractMethod1() {
  4. }
  5. @Override
  6. public void ParentAbstractMethod2() {
  7. }
  8. }
  9. interface ParentInter1 {
  10. void ParentAbstractMethod1();
  11. }
  12. interface ParentInter2 {
  13. void ParentAbstractMethod2();
  14. }

发生冲突分为以下几种情况。

抽象方法冲突

如果父类接口中定义了相同的抽象方法,只需重写一个即可 。

  1. public class Test implements ParentInter1, ParentInter2 {
  2. @Override
  3. public void ParentAbstractMethod() {
  4. }
  5. }
  6. interface ParentInter1 {
  7. void ParentAbstractMethod();
  8. }
  9. interface ParentInter2 {
  10. void ParentAbstractMethod();
  11. }

默认方法冲突

如果两个或多个独立定义的默认方法冲突,则必须显式覆盖超类型的方法。

可以通过 接口名.super.冲突的默认方法 来访问冲突的默认方法。

  1. public class Test implements ParentInter1, ParentInter2 {
  2. @Override
  3. public void ParentAbstractMethod() {
  4. ParentInter1.super.ParentAbstractMethod();
  5. ParentInter2.super.ParentAbstractMethod();
  6. }
  7. }
  8. interface ParentInter1 {
  9. default void ParentAbstractMethod() {
  10. System.out.println("this is ParentAbstractMethod1");
  11. }
  12. }
  13. interface ParentInter2 {
  14. default void ParentAbstractMethod() {
  15. System.out.println("this is ParenAbstractMethod2");
  16. }
  17. }

还有另外一种情况

已被其他候选覆盖的方法将被忽略。当超类型共享公共的祖先时,可能会出现这种情况。

  1. public class Test implements ParentInter2, ParentInter3 {
  2. public static void main(String[] args) {
  3. Test t = new Test();
  4. t.ParentAbstractMethod(); // this is ParenAbstractMethod2
  5. }
  6. }
  7. interface ParentInter1 {
  8. default void ParentAbstractMethod() {
  9. System.out.println("this is ParentAbstractMethod1");
  10. }
  11. }
  12. interface ParentInter2 extends ParentInter1 {
  13. default void ParentAbstractMethod() {
  14. System.out.println("this is ParenAbstractMethod2");
  15. }
  16. }
  17. interface ParentInter3 extends ParentInter1 {
  18. }

默认方法与实例方法冲突

实例方法优于默认方法。

  1. public class Test extends ParentClass implements ParentInter {
  2. public static void main(String[] args) {
  3. Test t = new Test();
  4. t.method(); // this is ParentClass method
  5. }
  6. }
  7. interface ParentInter {
  8. default void method() {
  9. System.out.println("this is ParentInter1 method");
  10. }
  11. }
  12. class ParentClass {
  13. public void method() {
  14. System.out.println("this is ParentClass method");
  15. }
  16. }

接口与接口之间的关系

接口可以拓展一个或多个接口,使用关键字 extends 关键字定义。

  1. interface ChildInter extends ParentInter1, ParentInter2 {
  2. }
  3. interface ParentInter1 {
  4. }
  5. interface ParentInter2 {
  6. }

发生冲突分为以下几种情况。

常量冲突

不能被继承,必须显式覆盖。

  1. public class Test {
  2. public static void main(String[] args) {
  3. System.out.println(ChildInter.s); // ChildInter
  4. }
  5. }
  6. interface ChildInter extends ParentInter1, ParentInter2 {
  7. String s = "ChildInter";
  8. }
  9. interface ParentInter1 {
  10. String s = "ParentInter1";
  11. }
  12. interface ParentInter2 {
  13. String s = "ParentInter2";
  14. }

静态方法(公共和私有)冲突

不冲突,静态方法属于类的不发生继承。

  1. public class Test {
  2. public static void main(String[] args) {
  3. // ChildInter.staticMethod(); 因为不继承,所以不能访问。
  4. }
  5. }
  6. interface ChildInter extends ParentInter1, ParentInter2 {
  7. }
  8. interface ParentInter1 {
  9. static void staticMethod() {
  10. System.out.println("this is ParentInter1");
  11. }
  12. }
  13. interface ParentInter2 {
  14. static void staticMethod() {
  15. System.out.println("this is ParentInter2");
  16. }
  17. }

私有方法冲突

不冲突,因为不会继承。

参考: