接口(interface)

1. 概述

接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要…则必须能…”的思想。继承是一个"是不是"的is-a关系,而接口实现则是 "能不能"的has-a关系。

  • 例如:电脑都预留了可以插入USB设备的USB接口,USB接口具备基本的数据传输的开启功能和关闭功能。你能不能用USB进行连接,或是否具备USB通信功能,就看你能否遵循USB接口规范

image-20220517211517846

  • 例如:Java程序是否能够连接使用某种数据库产品,那么要看该数据库产品能否实现Java设计的JDBC规范

image-20220325235434103

接口的本质是契约、标准、规范,就像我们的法律一样。制定好后大家都要遵守。

2. 定义格式

接口的定义,它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并不是类,而是另外一种引用数据类型。

引用数据类型:数组,类,枚举,接口,注解。

2.1 接口的声明格式

[修饰符] interface 接口名{  
    //接口的成员列表:  
    // 公共的静态常量  
    // 公共的抽象方法  
      
    // 公共的默认方法(JDK1.8以上)  
    // 公共的静态方法(JDK1.8以上)  
    // 私有方法(JDK1.9以上)  
}

示例代码:

package com.atguigu.interfacetype;  
​  
public interface USB3{  
    //静态常量  
    long MAX_SPEED = 500*1024*1024;//500MB/s  
​  
    //抽象方法  
    void in();  
    void out();  
​  
    //默认方法  
    default void start(){  
        System.out.println("开始");  
    }  
    default void stop(){  
        System.out.println("结束");  
    }  
​  
    //静态方法  
    static void show(){  
        System.out.println("USB 3.0可以同步全速地进行读写操作");  
    }  
}

2.2 接口的成员说明

在JDK8.0 之前,接口中只允许出现:

(1)公共的静态的常量:其中public static final可以省略

(2)公共的抽象的方法:其中public abstract可以省略

理解:接口是从多个相似类中抽象出来的规范,不需要提供具体实现

在JDK8.0 时,接口中允许声明默认方法静态方法

(3)公共的默认的方法:其中public 可以省略,建议保留,但是default不能省略

(4)公共的静态的方法:其中public 可以省略,建议保留,但是static不能省略

在JDK9.0 时,接口又增加了:

(5)私有方法

除此之外,接口中没有构造器,没有初始化块,因为接口中没有成员变量需要动态初始化。

3. 接口的使用规则

1、类实现接口(implements)

接口不能创建对象,但是可以被类实现(implements ,类似于被继承)。

类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类。实现的动作类似继承,格式相仿,只是关键字不同,实现使用 implements关键字。

【修饰符】 class 实现类  implements 接口{  
    // 重写接口中抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写  
    // 重写接口中默认方法【可选】  
}  
​  
【修饰符】 class 实现类 extends 父类 implements 接口{  
    // 重写接口中抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写  
    // 重写接口中默认方法【可选】  
}

image-20220514163212312

注意:

  1. 如果接口的实现类是非抽象类,那么必须重写接口中所有抽象方法

  2. 默认方法可以选择保留,也可以重写。

    重写时,default单词就不要再写了,它只用于在接口中表示默认方法,到类中就没有默认方法的概念了

  3. 接口中的静态方法不能被继承也不能被重写

举例:

interface USB{  //   
    public void start() ;  
    public void stop() ;      
}  
class Computer{  
    public static void show(USB usb){     
        usb.start() ;  
        System.out.println("=========== USB 设备工作 ========") ;  
        usb.stop() ;  
    }  
};  
class Flash implements USB{  
    public void start(){    // 重写方法  
        System.out.println("U盘开始工作。") ;  
    }  
    public void stop(){ // 重写方法  
        System.out.println("U盘停止工作。") ;  
    }  
};  
class Print implements USB{  
    public void start(){    // 重写方法  
        System.out.println("打印机开始工作。") ;  
    }  
    public void stop(){ // 重写方法  
        System.out.println("打印机停止工作。") ;  
    }  
};  
public class InterfaceDemo{  
    public static void main(String args[]){  
        Computer.show(new Flash()) ;  
        Computer.show(new Print()) ;  
​  
        c.show(new USB(){  
            public void start(){  
                System.out.println("移动硬盘开始运行");  
            }  
            public void stop(){  
                System.out.println("移动硬盘停止运行");  
            }  
        });  
    }  
};

2、接口的多实现(implements)

之前学过,在继承体系中,一个类只能继承一个父类。而对于接口而言,一个类是可以实现多个接口的,这叫做接口的多实现。并且,一个类能继承一个父类,同时实现多个接口。

实现格式:

【修饰符】 class 实现类  implements 接口1,接口2,接口3。。。{  
    // 重写接口中所有抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写  
    // 重写接口中默认方法【可选】  
}  
​  
【修饰符】 class 实现类 extends 父类 implements 接口1,接口2,接口3。。。{  
    // 重写接口中所有抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写  
    // 重写接口中默认方法【可选】  
}```


> 接口中,有多个抽象方法时,实现类必须重写所有抽象方法。**如果抽象方法有重名的,只需要重写一次**。

举例:

![image-20220514163311418](https://img.incxy.cn/wp-content/uploads/2025/picgo/image-20220514163311418.png)

![image-20220325235321778](https://img.incxy.cn/wp-content/uploads/2025/picgo/image-20220325235321778.png)

![1562216188519](https://img.incxy.cn/wp-content/uploads/2025/picgo/1562216188519.png)

**3、接口的多继承(extends)**

一个接口能继承另一个或者多个接口,接口的继承也使用 `extends` 关键字,子接口继承父接口的方法。

```java
定义父接口:

package com.atguigu.interfacetype;  
​  
public interface Chargeable {  
    void charge();  
    void in();  
    void out();  
}

定义子接口:

package com.atguigu.interfacetype;  
​  
public interface UsbC extends Chargeable,USB3 {  
    void reverse();  
}

定义子接口的实现类:

package com.atguigu.interfacetype;  
​  
public class TypeCConverter implements UsbC {  
    @Override  
    public void reverse() {  
        System.out.println("正反面都支持");  
    }  
​  
    @Override  
    public void charge() {  
        System.out.println("可充电");  
    }  
​  
    @Override  
    public void in() {  
        System.out.println("接收数据");  
    }  
​  
    @Override  
    public void out() {  
        System.out.println("输出数据");  
    }  
}

所有父接口的抽象方法都有重写。

方法签名相同的抽象方法只需要实现一次。

4、接口与实现类对象构成多态引用

实现类实现接口,类似于子类继承父类,因此,接口类型的变量与实现类的对象之间,也可以构成多态引用。通过接口类型的变量调用方法,最终执行的是你new的实现类对象实现的方法体。

接口的不同实现类:

package com.atguigu.interfacetype;  
​  
public class Mouse implements USB3 {  
    @Override  
    public void out() {  
        System.out.println("发送脉冲信号");  
    }  
​  
    @Override  
    public void in() {  
        System.out.println("不接收信号");  
    }  
}

package com.atguigu.interfacetype;  
​  
public class KeyBoard implements USB3{  
    @Override  
    public void in() {  
        System.out.println("不接收信号");  
    }  
​  
    @Override  
    public void out() {  
        System.out.println("发送按键信号");  
    }  
}  
​

测试类

package com.atguigu.interfacetype;  
​  
public class TestComputer {  
    public static void main(String[] args) {  
        Computer computer = new Computer();  
        USB3 usb = new Mouse();  
        computer.setUsb(usb);  
        usb.start();  
        usb.out();  
        usb.in();  
        usb.stop();  
        System.out.println("--------------------------");  
​  
        usb = new KeyBoard();  
        computer.setUsb(usb);  
        usb.start();  
        usb.out();  
        usb.in();  
        usb.stop();  
        System.out.println("--------------------------");  
​  
        usb = new MobileHDD();  
        computer.setUsb(usb);  
        usb.start();  
        usb.out();  
        usb.in();  
        usb.stop();  
    }  
}

5、使用接口的静态成员

接口不能直接创建对象,但是可以通过接口名直接调用接口的静态方法和静态常量。

package com.atguigu.interfacetype;  
​  
public class TestUSB3 {  
    public static void main(String[] args) {  
        //通过“接口名.”调用接口的静态方法 (JDK8.0才能开始使用)  
        USB3.show();  
        //通过“接口名.”直接使用接口的静态常量  
        System.out.println(USB3.MAX_SPEED);  
    }  
}

6、使用接口的非静态方法

  • 对于接口的静态方法,直接使用“接口名.”进行调用即可

    • 也只能使用“接口名."进行调用,不能通过实现类的对象进行调用
  • 对于接口的抽象方法、默认方法,只能通过实现类对象才可以调用

    • 接口不能直接创建对象,只能创建实现类的对象
package com.atguigu.interfacetype;  
​  
public class TestMobileHDD {  
    public static void main(String[] args) {  
        //创建实现类对象  
        MobileHDD b = new MobileHDD();  
​  
        //通过实现类对象调用重写的抽象方法,以及接口的默认方法,如果实现类重写了就执行重写的默认方法,如果没有重写,就执行接口中的默认方法  
        b.start();  
        b.in();  
        b.stop();  
​  
        //通过接口名调用接口的静态方法  
//        MobileHDD.show();  
//        b.show();  
        Usb3.show();  
    }  
}

4. JDK8中相关冲突问题

4.1 默认方法冲突问题

(1)类优先原则

当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的抽象方法重名,子类就近选择执行父类的成员方法。代码如下:

定义接口:

package com.atguigu.interfacetype;  
​  
public interface Friend {  
    default void date(){//约会  
        System.out.println("吃喝玩乐");  
    }  
}

定义父类:

package com.atguigu.interfacetype;  
​  
public class Father {  
    public void date(){//约会  
        System.out.println("爸爸约吃饭");  
    }  
}

定义子类:

package com.atguigu.interfacetype;  
​  
public class Son extends Father implements Friend {  
    @Override  
    public void date() {  
        //(1)不重写默认保留父类的  
        //(2)调用父类被重写的  
//        super.date();  
        //(3)保留父接口的  
//        Friend.super.date();  
        //(4)完全重写  
        System.out.println("跟康师傅学Java");  
    }  
}

定义测试类:

package com.atguigu.interfacetype;  
​  
public class TestSon {  
    public static void main(String[] args) {  
        Son s = new Son();  
        s.date();  
    }  
}

(2)接口冲突(左右为难)

  • 当一个类同时实现了多个父接口,而多个父接口中包含方法签名相同的默认方法时,怎么办呢?

接口(interface)

无论你多难抉择,最终都是要做出选择的。

声明接口:

package com.atguigu.interfacetype;  
​  
public interface BoyFriend {  
    default void date(){//约会  
        System.out.println("神秘约会");  
    }  
}

选择保留其中一个,通过“接口名.super.方法名"的方法选择保留哪个接口的默认方法。

package com.atguigu.interfacetype;  
​  
public class Girl implements Friend,BoyFriend{  
​  
    @Override  
    public void date() {  
        //(1)保留其中一个父接口的  
//        Friend.super.date();  
//        BoyFriend.super.date();  
        //(2)完全重写  
        System.out.println("跟康师傅学Java");  
    }  
​  
}

// 测试类

package com.atguigu.interfacetype;  
​  
public class TestGirl {  
    public static void main(String[] args) {  
        Girl girl = new Girl();  
        girl.date();  
    }  
}
  • 当一个子接口同时继承了多个接口,而多个父接口中包含方法签名相同的默认方法时,怎么办呢?

另一个父接口:

package com.atguigu.interfacetype;  
​  
public interface USB2 {  
    //静态常量  
    long MAX_SPEED = 60*1024*1024;//60MB/s  
​  
    //抽象方法  
    void in();  
    void out();  
​  
    //默认方法  
    public default void start(){  
        System.out.println("开始");  
    }  
    public default void stop(){  
        System.out.println("结束");  
    }  
​  
    //静态方法  
    public static void show(){  
        System.out.println("USB 2.0可以高速地进行读写操作");  
    }  
}

// 子接口:

package com.atguigu.interfacetype;  
​  
public interface USB extends USB2,USB3 {  
    @Override  
    default void start() {  
        System.out.println("Usb.start");  
    }  
​  
    @Override  
    default void stop() {  
        System.out.println("Usb.stop");  
    }  
}  
​

小贴士:

子接口重写默认方法时,default关键字可以保留。

子类重写默认方法时,default关键字不可以保留。

4.2 常量冲突问题

  • 当子类继承父类又实现父接口,而父类中存在与父接口常量同名的成员变量,并且该成员变量名在子类中仍然可见。

  • 当子类同时实现多个接口,而多个接口存在相同同名常量。

此时在子类中想要引用父类或父接口的同名的常量或成员变量时,就会有冲突问题。

父类和父接口:

package com.atguigu.interfacetype;  
​  
public class SuperClass {  
    int x = 1;  
}

package com.atguigu.interfacetype;  
​  
public interface SuperInterface {  
    int x = 2;  
    int y = 2;  
}

package com.atguigu.interfacetype;  
​  
public interface MotherInterface {  
    int x = 3;  
}

子类:

package com.atguigu.interfacetype;  
​  
public class SubClass extends SuperClass implements SuperInterface,MotherInterface {  
    public void method(){  
//        System.out.println("x = " + x);//模糊不清  
        System.out.println("super.x = " + super.x);  
        System.out.println("SuperInterface.x = " + SuperInterface.x);  
        System.out.println("MotherInterface.x = " + MotherInterface.x);  
        System.out.println("y = " + y);//没有重名问题,可以直接访问  
    }  
}

5. 接口的总结

  • 接口本身不能创建对象,只能创建接口的实现类对象,接口类型的变量可以与实现类对象构成多态引用。

  • 声明接口用interface,接口的成员声明有限制:

    • (1)公共的静态常量

    • (2)公共的抽象方法

    • (3)公共的默认方法(JDK8.0 及以上)

    • (4)公共的静态方法(JDK8.0 及以上)

    • (5)私有方法(JDK9.0 及以上)

  • 类可以实现接口,关键字是implements,而且支持多实现。如果实现类不是抽象类,就必须实现接口中所有的抽象方法。如果实现类既要继承父类又要实现父接口,那么继承(extends)在前,实现(implements)在后。

  • 接口可以继承接口,关键字是extends,而且支持多继承。

  • 接口的默认方法可以选择重写或不重写。如果有冲突问题,另行处理。子类重写父接口的默认方法,要去掉default,子接口重写父接口的默认方法,不要去掉default。

  • 接口的静态方法不能被继承,也不能被重写。接口的静态方法只能通过“接口名.静态方法名”进行调用。

6. 接口与抽象类之间的对比

image-20220328002053452

在开发中,常看到一个类不是去继承一个已经实现好的类,而是要么继承抽象类,要么实现接口。

Java基础

抽象类与抽象方法

2025-8-9 10:09:57

Java基础

单例(Singleton)设计模式

2025-8-9 10:27:34

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
今日签到
有新私信 私信列表
搜索