Kotlin - 运算符重载

Kotlin支持标准的算术运算表达式, 其中运算符被声明为相应类的成员。

Kotlin源代码中,我们可以自定义类型的运算符实现,即运算符的重载。这些运算符有固定的表示, 和固定的优先级。Kotlin为基本类型提供了固定名称的数值函数,比如二元运算符的左值和一元运算符的参数类型。

运算符的优先级

运算符的优先级

运算符重载

预定义的运算符的操作对象只能是基本数据类型,实际上,对于很多用户自定义类型,也需要有类似的运算操作。

运算符重载是对已有的运算符赋予多重含义,使同一个运算符作用于不同类型的数据导致不同类型的行为。

运算符重载的实质是函数重载。在实现过程中,首先把指定的运算表达式转化为对运算符函数的调用,运算对象转化为运算符函数的实参,然后根据实参的类型来确定需要调用达标函数,这个过程爱编译过程中完成。

一元运算符

算数运算符

表达式转换
+aa.unaryPlus()
-aa.unaryMinus()
!aa.not()


以表达式 +a为例,编译器的运行流程如下:

1. 确定a的类型,假设为T
2. 查找具有操作符修饰符的无参函数unaryPlus(),并且没有用于接收者T的参数,比如数值函数或扩展函数。
3. 如果函数返回类型R,那么它必须是T的子类型。


注:这些操作符和其它的一样, 其操作的数据都被优化为基本类型并且不会产生多余的开销

自增自减

这里写图片描述

计算表达式的效果


1. 把 a 的初始值存储在 a0 中
2. 把 a.inc() 的结果作用在 a 上
3. 把 a0 作为表达式的返回值

二元操作符

算术操作符

表达式转换
a + ba.plus(b)
a - ba.minus(b)
a * ba.times(b)
a / ba.div(b)
a % ba.mod(b)
a..ba.rangeTo(b)

编辑器只会处理“转换列中的表达式”

表达式转换
a in bb.contains(a)
a !in b!b.contains(a)

in 和 !in 的产生步骤是一样的, 但参数顺序是相反的

标志转换
a[i]a.get(i)
a[i, j]a.get(i, j)
a[i_1, …, i_n]a.get(i_1, … , i_n)
a[i] = ba.set(i, b)
a[i,j] =ba.set(i, j, b)
a[i_1, … , i_n] = ba.set(i_1,… ,o_n,b)

方括号被转换为 get set 函数

标志转换
a(i)a.invoke(i)
a(i, j)a.invoke(i, j)
a(i_1, … , i_n)a.invoke(i_1, …, i_n)

括号被转换为带有正确参数的 invoke 参数

表达式转换
a += ba.plusAssign(b)
a -= ba.minusAssign(b)
a *= ba.timesAssign(b)
a /= ba.divAssign(b)
a %= ba.modAssign(b)

以a += b为例分析编辑器运行

  • 如果右列的函数可用
    1. 确保相应的二进制函数(即plusAssign()的plus())也可用,否则发送错误报告
    2. 确保其返回类型为Unit,否则发送错误报告
      3.生成a.plusAssign(b)代码端
  • 如果右列的函数不可用,尝试为a = a + b生成代码(包括类型检查:+ b的类型必须是a的子类型)。
表达式转换
a == ba?.equals(b) ?: b.identityEquals(null)
a != b!(a?.equals(b) ?: b.identityEquals(null))


注意 === !== 是不允许重载的

  1. ==

    1. 如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等(若类型不同,高级转化为基础类型);
    2. 如果作用于引用类型的变量,则比较的是所指向的对象的地址
  2. equals

    1. equals方法不能作用于基本数据类型的变量
    2. 如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
      3.诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。
  3. ===
    1. 对于基本数据类型,如果类型不同,其结果就是不等。如果同类型相比,与“==”一致,直接比较其存储的 “值”是否相等;
    2. 对于引用类型,与“==”一致,比较的是所指向的对象的地址
表达式转换
a > ba.compareTo(b) > 0
a < ba.compareTo(b) < 0
a >= ba.compareTo(b) >= 0
a <= ba.compareTo(b) <= 0

所有的比较都转换为 compareTo 的调用, 这个函数需要返回 Int 值

位运算

对于位运算,Kotlin 并没有提供特殊的操作符, 只是提供了可以叫中缀形式的方法, 比如:

val x = (1 shl 2) and 0x000FF000

下面是全部的位运算操作符(只可以用在 Int 和 Long 类型):

  • shl(bits) – 有符号左移 (相当于Java <<)
  • shr(bits) – 有符号右移 (相当于Java >>)
  • ushr(bits) – 无符号右移(相当于Java >>>)
  • and(bits) – 按位与
  • or(bits) – 按位或
  • xor(bits) – 按位异或
  • inv() – 按位取反

示例代码

Data Class

data class OperatorOverride(var name: String, var age: Int) {
    // 重载 +a
    operator fun unaryPlus() : OperatorOverride{
        age = age.plus(100)
        return  this
    }

    // 重载 a++
    operator fun inc() : OperatorOverride {
        age += 10
        return  this
    }

    // 重载 a+b
    operator fun plus(oo: OperatorOverride): OperatorOverride {
        age += oo.age
        return  this
    }
    // 重载 equals
    override fun equals(other: Any?): Boolean {
        if (other is OperatorOverride) {
            return this.age > other.age
        }
        return false
    }
}

Test

fun main(args: Array<String>) {

    var oo : OperatorOverride = OperatorOverride("zhang", 10)

    println("----------------------------------")

    println("原oo = ${oo}")
    +oo
    println("新oo = ${oo}")

    println("----------------------------------")

    println("----------------------------------")

    println("原oo = ${oo}")
    oo++
    println("新oo = ${oo}")

    println("----------------------------------")


    println("----------------------------------")
    val  o : OperatorOverride = OperatorOverride("zhao", 43)
    println("原oo = ${oo}")
    println("新oo = ${oo + o}")

    println("----------------------------------")

    println("----------------------------------")

    println(oo.equals(o)) // oo的age为120,o的age为43,故返回true

    println("----------------------------------")
}

Log打印

----------------------------------
原oo = OperatorOverride(name=zhang, age=10)
新oo = OperatorOverride(name=zhang, age=110)
----------------------------------
----------------------------------
原oo = OperatorOverride(name=zhang, age=110)
新oo = OperatorOverride(name=zhang, age=120)
----------------------------------
----------------------------------
原oo = OperatorOverride(name=zhang, age=120)
新oo = OperatorOverride(name=zhang, age=163)
----------------------------------
----------------------------------
true
----------------------------------

版权声明:本文为IO_Field原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。