从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 新闻合订本
    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 新闻合订本
    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • JavaSE

    • 我的 Java 学习路线
    • 安装 Java
    • Java 数据类型

    • Java 多版本配置
    • 面向对象

      • 枚举类
      • static 关键字
      • classpath:JVM 查找类的机制
      • 包:Java 组织类的方式
      • jar 包
      • class 版本
      • 抽象类
      • 接口
        • 定义接口
        • 实现接口
        • 接口继承
        • 继承关系
        • default 方法
        • 抽象类和接口的区别
        • 什么时候使用接口?
        • 参考
      • 访问性修饰符
      • 非访问性修饰符
      • 内部类
    • Java 核心类

    • IO

    • Java 与时间

    • 异常处理

    • 哈希和加密算法

    • Java8 新特性

    • 网络编程

  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

  • SpringMVC

  • SpringBoot

  • Java
  • JavaSE
  • 面向对象
2023-02-08
目录

接口

# 接口

一个类,如果实现了一个接口,那么它必须实现接口中定义的所有方法。一个类,继承一个抽象类,那么它必须重写抽象类中定义的所有抽象方法,可以不用重写抽象类中定义的普通方法。

# 定义接口

在抽象类中,抽象方法本质上是定义接口规范:即规定高层类的接口,从而保证所有子类都有相同的接口实现,这样,多态就能发挥出威力。

如果一个抽象类没有字段,所有方法全部都是抽象方法:

abstract class Person {
    public abstract void run();
    public abstract String getName();
}
1
2
3
4

就可以把该抽象类改写为接口:interface。

在 Java 中,使用 interface 可以声明一个接口:

interface Person {
    void run();
    String getName();
}
1
2
3
4

所谓 interface,就是比抽象类还要抽象的纯抽象接口,因为它连字段都不能有。因为接口定义的所有方法默认都是 public abstract 的,所以这两个修饰符不需要写出来(写不写效果都一样)。

注意:

  1. interface 可以看成是一种特殊的类,源代码文件也是以 .java 结尾,编译时也是一个独立的字节码文件。

  2. 所有类共享一个根类 Object,但是接口没有根

  3. 和抽象类相似,不能用 new 操作符创建 interface 的实例。

  4. 虽然 Interface 不能有字段,但是可以有常量。

  5. 接口中所有数据域都是 public static final 修饰的,所有方法都是 public abstract 修饰的,因此可以忽略,如下两个接口定义是等价的:

    public interface T {
        public static final int K =1;
        public abstract void p();
    }
    
    public interface T {
        int K = 1;
        void p();
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

# 实现接口

当一个具体的 class 去实现一个 interface 时,需要使用 implements 关键字。

class Student implements Person {
    private String name;

    public Student(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(this.name + " run");
    }

    @Override
    public String getName() {
        return this.name;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

注意,必须得实现接口中的方法,否则会报错的,例如当我们没有实现 getName 方法:

$ javac Student.java
Student.java:1: 错误: Student不是抽象的, 并且未覆盖Person中的抽象方法getName()
public class Student implements Person {
       ^
1 个错误
1
2
3
4
5

一个类实现一个接口,其实也是相当于继承了这个接口。一个接口类型的变量可以引用任何实现该接口的类的实例,这样我们就可以面向抽象编程了(参考上一节的抽象类)

在 Java 中,一个类只能继承自另一个类,不能从多个类继承。但是,一个类可以实现多个 interface:

class Student implements Person, Hello { // 实现了两个interface
    ...
}
1
2
3

# 接口继承

一个 interface 可以继承自另一个 interface。interface 继承自 interface 使用 extends,它相当于扩展了接口的方法。例如:

interface Person {
    void run();
    String getName();
}

public interface Hello extends Person {
  
}
1
2
3
4
5
6
7
8

此时,Person 接口继承自 Hello 接口,因此,Person 接口现在实际上有 3 个抽象方法签名,其中一个来自继承的 Hello 接口。

注意,接口可以继承其他接口,但不能继承其他类。

综上,一个类只能继承一个父类,但可以同时实现多个接口。

# 继承关系

合理设计 interface和 abstract class的继承关系,可以充分复用代码。一般来说,公共逻辑适合放在 abstract class中,具体逻辑放到各个子类,而接口层次代表抽象程度。

举一个实际的例子,参考 Java 的集合类定义的一组接口、抽象类以及具体子类的继承关系:

┌───────────────┐
│   Iterable    │
└───────────────┘
        ▲                ┌───────────────────┐
        │                │      Object       │
┌───────────────┐        └───────────────────┘
│  Collection   │                  ▲
└───────────────┘                  │
        ▲     ▲          ┌───────────────────┐
        │     └──────────│AbstractCollection │
┌───────────────┐        └───────────────────┘
│     List      │                  ▲
└───────────────┘                  │
              ▲          ┌───────────────────┐
              └──────────│   AbstractList    │
                         └───────────────────┘
                                ▲     ▲
                                │     │
                                │     │
                     ┌────────────┐ ┌────────────┐
                     │ ArrayList  │ │ LinkedList │
                     └────────────┘ └────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

在使用的时候,实例化的对象永远只能是某个具体的子类,但总是通过接口去引用它,因为接口比抽象类更抽象:

List list = new ArrayList(); // 用List接口引用具体子类的实例
Collection coll = list; // 向上转型为Collection接口
Iterable it = coll; // 向上转型为Iterable接口
1
2
3

# default 方法

在接口中,可以定义 default 方法。例如,定义一个 run 方法:

public interface InterfaceWithDefault {
  String getName();
  default void run(){
    System.out.println(getName() + " run ");
  };
}
1
2
3
4
5
6

实现类可以不必覆写 default 方法。default 方法的目的是,当我们需要给接口新增一个方法时,会涉及到修改全部子类。如果新增的是 default 方法,那么子类就不必全部修改,只需要在需要覆写的地方去覆写新增方法。

然后实现该接口:

public class TestDefault {
  public static void main(String[] args) {
    InterfaceWithDefault stu = new Student("Peter JXL");  
    stu.run();
  }
}

class Student implements InterfaceWithDefault{
  private String name;

  public Student(String name){
    this.name = name;
  }

  public String getName(){
    return this.name;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

输出结果:

Peter JXL run
1

# 抽象类和接口的区别

抽象类和接口的对比如下:

abstract class interface
继承 只能 extends 一个 class 可以 implements 多个 interface
字段 可以定义实例字段 不能定义实例字段
抽象方法 可以定义抽象方法 可以定义抽象方法
非抽象方法 可以定义非抽象方法 可以定义 default 方法

还有一点,default 方法和抽象类的普通方法是有所不同的。因为 interface 没有字段,default 方法无法访问字段,而抽象类的普通方法可以访问实例字段。

# 什么时候使用接口?

一般情况下,我们会为类名取一个名词,为接口名取一个形容词或名词。

抽象类和接口都是用来明确多个对象的共同特征的。那么该如何确定在什么情况下应该使用接口,什么情况下应该使用类呢?

一般来说,清晰描述父.子关系的强的“是一种” 的关系( strong is-a relationship) 应该用类建模。例如,因为公历是一种日历,所以,类 java.util.GregorianCalendar 和 java.util.Calendar 是用类继承建模的。

弱的 “是一种” 的关系(weak is-a relationship) 也称为类属关系(is-kind-ofrelationship), 它表明对象拥有某种属性,可以用接口来建模。

例如,所有的字符串都是可比较的,而且数字也是可以比较的,因此,Java 定义了一个 Comparable 接口,String 类和数值类实现这个接口。

但是如果我们用抽象类的方式来实现,让数值类和字符串都继承某个抽象类,完全是没必要的,因为数字有数字的比较方法,字符串有字符串的比较方法,学生(自己定义的类)也有自己的比较方法,所以子类是必须要覆写父类的方法的,并且让这几个完全没有关联的类继承一个抽象类,从逻辑上不太适合。

统一标准的目的,是大家都知道这个是做什么的,但是具体不用知道具体怎么做。

# 参考

接口 - 廖雪峰的官方网站 (opens new window)

Java 中的接口有什么作用? - 知乎

Java 中的接口有什么作用? - Dion 的回答 - 知乎 (opens new window)

上次更新: 2024/9/30 20:09:39
抽象类
访问性修饰符

← 抽象类 访问性修饰符→

最近更新
01
新闻合订本 2025-10
10-31
02
2025 年 10 月记
10-30
03
用 AI 批量优化思源笔记排版
10-15
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式