前言

理解好了抽象的概念,进一步学习接口

接口的设计弥补了Java不能多继承的缺陷

本篇文章将介绍Java接口的相关内容


关于接口

可以将接口理解为:多个类的公共规范

接口是一种引用数据类型,最重要的内容就是其中的抽象方法

接口的定义格式:

public interface 接口名称 {
    // 接口内容
}

在Java7中,接口可以包含:

  • 常量(定义后不可更改)

  • 抽象方法abstract

在Java8中,又可以定义:

  • 默认方法default

  • 静态方法static

在Java9中,还可以包含:

  • 私有方法private

注意:接口是没有静态代码块或者构造方法

使用

基本使用

接口使用规范:

  1. 接口不能直接使用,必须有一个实现类来实现该接口
public class 实现类名称 implements 接口名称 {
    // ...
}
  1. 接口的实现类必须覆盖重写(实现)接口中所有的抽象方法
  2. 创建实现类的对象,进行使用

在定义接口的抽象方法时需要注意格式

public abstract 返回值类型 方法名称(参数列表);

  • 接口当中的抽象方法,修饰符必须是两个固定的关键字:public abstract

  • 这两个关键字修饰符,可以选择性地省略(省略后仍为抽象方法)

定义接口InterfaceDemo

public interface InterfaceDemo {
    public abstract void method1();
    void method2();
}

定义接口实现类InterfaceDemoImpl

public class InterfaceDemoImpl implements InterfaceDemo {
    @Override
    public void method1() {
        System.out.println("第一个方法");
    }

    @Override
    public void method2() {
        System.out.println("第二个方法");
    }
}

定义使用类Demo

public class Demo {
    public static void main(String[] args) {
        InterfaceDemoImpl Demo = new InterfaceDemoImpl();
        Demo.method1();
        Demo.method2();
    }
}

结果如下:

第一个方法
第二个方法

默认方法

接口中的默认方法,可以解决接口升级的问题

public default 返回值类型 方法名称(参数列表) {
    方法体
}

假设一个项目已经投入使用,这时在接口升级中准备添加一个新的方法,但是该接口的所有实现类都需要重写新的方法。如此一来升级维护成本太大,所以在Java8之后,允许接口定义默认方法,免去接口实现类重写的麻烦

  • 实现类可以重写接口中定义的默认方法

  • 实现类可以直接使用接口中定义的默认方法

定义接口InterfaceDemo

public interface InterfaceDemo {
    public abstract void method();

    public default void method1() {
        System.out.println("接口默认方法一");
    }

    default void method2() {
        System.out.println("接口默认方法二");
    }
}

定义接口实现类InterfaceDemoImpl

public class InterfaceDemoImpl implements InterfaceDemo {
    @Override
    public void method() {
        System.out.println("重写接口的抽象方法");
    }

    @Override
    public void method1() {
        System.out.println("重写接口的默认方法一");
    }
}

定义使用类Demo

public class Demo {
    public static void main(String[] args) {
        InterfaceDemoImpl Demo = new InterfaceDemoImpl();
        Demo.method();
        Demo.method1();
        Demo.method2();
    }
}

结果如下:

重写接口的抽象方法
重写接口的默认方法一
接口默认方法二

静态方法

Java8后还允许接口定义静态方法,格式如下:

public static 返回值类型 方法名称(参数列表) {
    方法体
}

注意:

  • 必须有public关键字修饰,不然其他类无法访问

  • 正确用法:不可以通过接口的实现类来调用静态方法,直接按照调用格式使用:
    接口名称.静态方法名(参数);

定义接口InterfaceDemo

public interface InterfaceDemo {
    public static void method() {
        System.out.println("接口的静态方法");
    }
}

定义使用类Demo

public class Demo {
    public static void main(String[] args) {
        InterfaceDemo.method();
    }
}

结果如下:

接口的静态方法

常量

接口当中也可以定义成员变量,但是必须使用public static final三个关键字进行修饰,从效果上看,这其实就是接口的常量

public static final 数据类型 常量名称 = 数据值;

注意:

  • 接口当中的常量,可以省略public static final(省略不写效果一样)

  • 接口当中的常量,必须进行赋值

  • 推荐接口常量的命名规则:使用完全大写的字母,用下划线进行分隔

定义接口InterfaceDemo

public interface InterfaceDemo {
    public static final String STR1 = "接口常量一";
    String STR2 = "接口常量二";
}

定义使用类Demo

public class Demo {
    public static void main(String[] args) {
        System.out.println(InterfaceDemo.STR1);
        System.out.println(InterfaceDemo.STR2);
    }
}

结果如下:

接口常量一
接口常量二

接口的多实现

一个类的直接父类是唯一的,但是一个类可以同时实现多个接口

public class InterfaceImpl implements InterfaceA, InterfaceB {
    // 覆盖重写所有抽象方法
}

使用时需要注意

  • 如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可
  • 如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类
  • 如果实现类所实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写
  • 一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法(可以不用重写)

定义接口InterfaceDemoA

public interface InterfaceDemoA {
    public abstract void methodA();

    public default void method() {
        System.out.println("接口A的重名默认方法");
    }
}

定义接口InterfaceDemoB

public interface InterfaceDemoB {
    public abstract void methodB();

    public default void method() {
        System.out.println("接口B的重名默认方法");
    }
}

定义父类Father

public class Father {
    public void method_Father() {
        System.out.println("父类方法");
    }

    public void method() {
        System.out.println("父类重名方法");
    }
}

定义子类/接口实现类Son

public class Son extends Father implements InterfaceDemoA,InterfaceDemoB {
    @Override
    public void methodA() {
        System.out.println("重写接口A的方法");
    }

    @Override
    public void methodB() {
        System.out.println("重写接口B的方法");
    }

    @Override
    public void method() {
        System.out.println("重写接口和父类的重名方法");
    }
}

定义使用类Demo

public class Demo {
    public static void main(String[] args) {
        Son son = new Son();
        son.methodA();
        son.methodB();
        son.method_Father();
        son.method();
    }
}

结果如下:

重写接口A的方法
重写接口B的方法
父类方法
重写接口和父类的重名方法

接口的多继承

接口与接口之间是多继承

public interface InterfaceDemo extends InterfaceA, InterfaceB {
    // 覆盖重写所有冲突的默认方法
}

使用时注意:

  • 可以不用重写父接口的抽象方法(冲突也不要紧,因为实现类总要重写)
  • 多个父接口当中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写

定义父接口InterfaceA

public interface InterfaceA {
    public abstract void methodA();
    public abstract void methodCommon();
    public default void methodDefault() {
        System.out.println("父接口A的重名默认方法");
    }
}

定义父接口InterfaceB

public interface InterfaceB {
    public abstract void methodB();
    public abstract void methodCommon();
    public default void methodDefault() {
        System.out.println("父接口B的重名默认方法");
    }
}

定义子接口InterfaceDemo

public interface InterfaceDemo extends InterfaceA, InterfaceB {
    public abstract void methodC();
    @Override
    public default void methodDefault() {
        System.out.println("重写父接口默认重名方法");
    }
}

定义子接口实现类InterfaceDemoImpl

public class InterfaceDemoImpl implements InterfaceDemo {
    @Override
    public void methodA() {
        System.out.println("重写父接口A的方法");
    }

    @Override
    public void methodB() {
        System.out.println("重写父接口B的方法");
    }

    @Override
    public void methodC() {
        System.out.println("重写子接口的方法");
    }

    @Override
    public void methodCommon() {
        System.out.println("重写父接口的重名方法");
    }
}

定义实现类Demo

public class Demo {
    public static void main(String[] args) {
        InterfaceDemoImpl Demo = new InterfaceDemoImpl();
        Demo.methodA();
        Demo.methodB();
        Demo.methodC();
        Demo.methodCommon();
        Demo.methodDefault();
    }
}

结果如下:

重写父接口A的方法
重写父接口B的方法
重写子接口的方法
重写父接口的重名方法
重写父接口默认重名方法