Kotlin 中的运算符重载在 class 文件中是如何实现的?(第一部分)

Kotlin 中的运算符重载在 class 文件中是如何实现的?

结论

以 + 这个二元运算符为例,

  1. 如果 kotlin 代码有 operator fun plus(...) 这样的方法定义,那么 class 文件中会有对应的 plus 方法出现。
  2. 反之,如果 class 文件中有签名正确的 plus 方法(即使这个方法是通过编译 java 代码而生成的),那么 kotlin 也可以将其视为运算符重载

代码

我们用以下代码来进行探索,请将其保存为 Vector.kt

kotlin 复制代码
data class Vector(val x: Double, val y: Double) {
  operator fun plus(other: Vector): Vector {
    return Vector(x + other.x, y + other.y)
  }
}

fun main(args: Array<String>) {
  val v1 = Vector(1.0, 0.0)
  val v2 = Vector(0.0, 1.0)
  val sum = v1 + v2
  println("The sum is: $sum")
}

用 kotlinc Vector.kt 命令编译之后,会生成 Vector.class 和 VectorKt.class。 在 Intellij IDEA 中使用 Show Kotlin Bytecode 功能可以看到这两个 class 文件的内容。 通过对比以下两者,会发现 kotlin 代码中的 v1 + v2 和 java 文件里的 v1.plus(v2) 是对应的。

  • Vector.kt
  • 对 VectorKt.class 进行 decompile 操作而得到的 java 文件

这么说来 Vector.class 中应该有名为 plus 的方法。 对 Vector.class 进行 decompile 操作后,会得到一个 java 文件,在这个 java 文件中可以找到一个名为 plus 的方法。

看起来 kotlin 代码中重载的运算符在 class 文件中会变成普通的方法(例如 kotlin 里重载的 + 操作,在 class 文件中会转化为名为 plus 的方法)。

如果上述猜测成立的话,即使我们用 java 代码定义 plus 方法,kotlin 代码应该也可以把它当作运算符重载来处理。

我们写一点 java 代码来验证一下。下面定义了一个简单的复数类,其中有一个 plus 方法,可以将两个复数相加(请将下方的 java 代码保存为 ComplexNumber.java)。

java 复制代码
public class ComplexNumber {
  private double r;
  private double i;

  public ComplexNumber(double r, double i) {
    this.r = r;
    this.i = i;
  }

  public double getR() {
    return r;
  }

  public double getI() {
    return i;
  }

  public ComplexNumber plus(ComplexNumber another) {
    return new ComplexNumber(this.r + another.r, this.i + another.i);
  }
}

然后再通过以下的 kotlin 代码来使用上面的复数类(请将下方的 kotlin 代码保存为 A.kt)

kotlin 复制代码
fun main(args: Array<String>) {
  val cn1 = ComplexNumber(1.0, 1.0)
  val cn2 = ComplexNumber(1.0, 1.0)
  val sum = cn1 + cn2
  println("r is: ${sum.r}")
  println("i is: ${sum.i}")
}

以下命令可以编译 ComplexNumber.java 和 A.kt,以及运行 A.kt 中的 main 方法。

bash 复制代码
javac -g -parameters ComplexNumber.java
kotlinc -cp . A.kt
kotlin AKt

运行结果如下 ⬇️

运行结果符合预期。

不过上面的描述毕竟只是猜测,有没有比较可靠的文档呢?

Operator overloading 一文中的 Arithmetic operators 小节 提到

看来 +/-/*///%/../..< 这几个 operator 都会被 compiler 转化为对应的方法调用(对应的具体方法请参考上图)。

另外,我在 Calling Java from Kotlin 一文的 Operators 小节 中找到到了如下的内容

可见,如果在 java 中定义好 plus/minus/times/div 等方法,然后从 kotlin 代码中以运算符重载的方式去调用这些方法是可行的。

参考资料

kotlinlang.org/ 网站关于以下内容的介绍

  1. Operator overloading
  2. Calling Java from Kotlin
相关推荐
蛋蛋的就会顺顺的21 分钟前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
需要8261 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
小 黄 鸡1 小时前
HashMap 面试必会知识点详解(JDK 8)
java·面试·职场和发展
伯恩bourne3 小时前
Spring Boot Bean 注册的两种方式:@Component 家族 vs @Configuration + @Bean
java·spring boot·后端
silvamux_3 小时前
curl 测试 OpenAI 兼容 API 的完整流程
java·人工智能·缓存·ai·oneapi
省钱兄--zs4 小时前
深圳24小时自助健身房软硬件解决方案实战指南与开发流程详解
java·数据仓库·spring boot·小程序·架构
顽疲4 小时前
Java vue 养老系统源码详解:月账单 care_month_bill 与 Quartz 扣费 Job 实践
java·开发语言·vue.js·vue养老·springboot养老·java养老
Wang's Blog4 小时前
Java 项目实战: 交友项目 - 安装开发工具与环境准备
java·开发语言·交友
用户21296835261684 小时前
开源了一个 Java 多智能体 LLM 框架 Baton:一个依赖,把 Agent 循环、工具调用、记忆、编排全配齐
java·llm
helmsail5 小时前
05 管理活动与选品
java