1. 什么是 API?

API(Application Programming Interface)描述了软件组件之间如何交互。

这种交互可以是两个应用通过网络通信,比如一个 HTTP API 可以通过 OpenAPI 规范定义,其他应用可以根据这个规范来调用接口。它会明确请求的格式、路径、参数以及返回值的结构。

但 API 不仅限于网络接口。例如 Java 中的类库也有 API,它定义了哪些类、方法、字段是对外暴露的,其他程序或库可以如何调用它。

API 是抽象接口的集合,不局限于网络。

比如:

  • 数据库的 schema 也是一种 API,因为它定义了数据的结构和约束
  • 消息队列中的消息格式也可以视为 API
  • 文件格式(如 CSV、JSON)也可以是 API 的一部分

⚠️ 改变这些 API 都可能影响依赖它的系统,哪怕它们不是传统意义上的接口。


2. 什么是 ABI?

ABI(Application Binary Interface)是 API 在编译后的二进制形式中所表现出来的接口。

在 Java 中,一个类库的 API 是它的源代码接口,而 ABI 则是编译后的 .class 文件。JVM 通过 ABI 来识别类和方法。

2.1. API 与 ABI 的关系

虽然 ABI 通常由 API 编译而来,但它们之间并不总是完全同步:

  • 某些 API 改动不会影响 ABI

    比如 Java 的泛型擦除:

    public List<String> getStrings() {}
    public List<Integer> getInts() {}
    

    这两个方法在源码中不同,但编译后都变成:

    public List getStrings() {}
    public List getInts() {}
    

    所以从 ABI 角度看,这两个方法是重复的,会导致编译错误。

  • 某些 ABI 改动不影响 API

    比如用不同版本的 Java 编译器编译相同的源代码,生成的 .class 文件可能不同(如 Java 8 vs Java 17),但 API 是一致的。


2.2. 有些 API 没有对应的 ABI

不是所有 API 都有 ABI:

  • ✅ 解释型语言如 Python、JavaScript 没有编译输出,因此没有 ABI
  • ✅ HTTP 接口的 API 是请求/响应格式,但它的 ABI 是网络上传输的字节流(包括 TCP/IP、SSL、HTTP 协议细节等)

⚠️ 但在实际开发中,我们通常不会关心 HTTP 的 ABI,因为我们通过 HTTP 客户端库(如 Apache HttpClient、OkHttp)来隐藏这些细节。


3. API 与 ABI 的兼容性

当依赖的库发生 API 或 ABI 改动时,我们的应用可能需要做相应调整。

3.1. ABI 兼容性

  • ✅ 如果 ABI 未变,即使库更新了,我们的应用也无需重新编译
  • ✅ 如果 ABI 改变了,但 API 没变,我们需要重新编译应用,但不需要修改代码

例如:类中某个字段的内存偏移变了,或者常量值变了

3.2. API 兼容性

  • ❌ 如果 API 改动是破坏性的(如删除方法、改变参数),我们必须修改代码才能继续使用

例如:方法签名改变、删除字段、接口变更等


4. 版本控制与兼容性(Semantic Versioning)

为了清晰表达接口变更的影响,建议使用 语义化版本号(Semantic Versioning)主版本号.次版本号.修订号

4.1. 版本号含义

版本层级 示例 含义
主版本号 2.0.0 API 或 ABI 有重大不兼容变更
次版本号 1.2.0 增加了新功能,但 API 兼容
修订版本 1.1.1 仅修复 bug,API 与 ABI 均未变

4.2. 实际场景举例

  • 1.1.0 → 1.1.1:仅修复 bug,无需任何改动
  • 1.1.0 → 1.2.0:新增了方法或字段,旧代码仍可运行,但可能需要重新编译
  • 1.2.0 → 2.0.0:有破坏性变更,需要修改代码才能升级

5. 总结

对比点 API ABI
定义 源代码层面的接口 二进制层面的接口
示例 类/方法定义、HTTP 接口 .class 文件、网络字节流
改动影响 可能需要修改代码 可能需要重新编译
版本策略 主要影响主版本号 主要影响次版本号

理解 API 与 ABI 的区别,有助于我们在做接口设计、版本管理、依赖升级时更准确地评估影响范围,避免踩坑。


原始标题:Differences Between APIs and ABIs