Kotlin学习系列——运算符重载

Love The Way You Lie 2023-06-28 08:56 81阅读 0赞

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

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

运算符的优先级

运算符的优先级

运算符重载

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

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

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

一元运算符

算数运算符






















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

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

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

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

自增自减

这里写图片描述

计算表达式的效果

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

二元操作符

算术操作符


































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

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


















表达式 转换
a in b b.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] = b a.set(i, b)
a[i,j] =b a.set(i, j, b)
a[i_1, … , i_n] = b a.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 += b a.plusAssign(b)
a -= b a.minusAssign(b)
a *= b a.timesAssign(b)
a /= b a.divAssign(b)
a %= b a.modAssign(b)

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

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

















表达式 转换
a == b a?.equals(b) ?: b.identityEquals(null)
a != b !(a?.equals(b) ?: b.identityEquals(null))

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

  1. ==

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

  3. 如果作用于引用类型的变量,则比较的是所指向的对象的地址

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

























  • 表达式 转换
    a > b a.compareTo(b) > 0
    a < b a.compareTo(b) < 0
    a >= b a.compareTo(b) >= 0
    a <= b a.compareTo(b) <= 0

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

    位运算

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

    1. val x = (1 shl 2) and 0x000FF000
  1. 1
  2. 下面是全部的位运算操作符(只可以用在 Int Long 类型):
  3. * shl(bits) 有符号左移 (相当于Java <<)
  4. * shr(bits) 有符号右移 (相当于Java >>)
  5. * ushr(bits) 无符号右移(相当于Java >>>)
  6. * and(bits) 按位与
  7. * or(bits) 按位或
  8. * xor(bits) 按位异或
  9. * inv() 按位取反
  10. # 示例代码 #
  11. # Data Class #
  12. data class OperatorOverride(var name: String, var age: Int) {
  13. // 重载 +a
  14. operator fun unaryPlus() : OperatorOverride{
  15. age = age.plus(100)
  16. return this
  17. }
  18. // 重载 a++
  19. operator fun inc() : OperatorOverride {
  20. age += 10
  21. return this
  22. }
  23. // 重载 a+b
  24. operator fun plus(oo: OperatorOverride): OperatorOverride {
  25. age += oo.age
  26. return this
  27. }
  28. // 重载 equals
  29. override fun equals(other: Any?): Boolean {
  30. if (other is OperatorOverride) {
  31. return this.age > other.age
  32. }
  33. return false
  34. }
  35. }
  36. 1
  37. 2
  38. 3
  39. 4
  40. 5
  41. 6
  42. 7
  43. 8
  44. 9
  45. 10
  46. 11
  47. 12
  48. 13
  49. 14
  50. 15
  51. 16
  52. 17
  53. 18
  54. 19
  55. 20
  56. 21
  57. 22
  58. 23
  59. 24
  60. 25
  61. 26
  62. # Test #
  63. fun main(args: Array<String>) {
  64. var oo : OperatorOverride = OperatorOverride("zhang", 10)
  65. println("----------------------------------")
  66. println("原oo = ${oo}")
  67. +oo
  68. println("新oo = ${oo}")
  69. println("----------------------------------")
  70. println("----------------------------------")
  71. println("原oo = ${oo}")
  72. oo++
  73. println("新oo = ${oo}")
  74. println("----------------------------------")
  75. println("----------------------------------")
  76. val o : OperatorOverride = OperatorOverride("zhao", 43)
  77. println("原oo = ${oo}")
  78. println("新oo = ${oo + o}")
  79. println("----------------------------------")
  80. println("----------------------------------")
  81. println(oo.equals(o)) // oo的age为120,o的age为43,故返回true
  82. println("----------------------------------")
  83. }
  84. 1
  85. 2
  86. 3
  87. 4
  88. 5
  89. 6
  90. 7
  91. 8
  92. 9
  93. 10
  94. 11
  95. 12
  96. 13
  97. 14
  98. 15
  99. 16
  100. 17
  101. 18
  102. 19
  103. 20
  104. 21
  105. 22
  106. 23
  107. 24
  108. 25
  109. 26
  110. 27
  111. 28
  112. 29
  113. 30
  114. 31
  115. 32
  116. 33
  117. 34
  118. # Log打印 #
  119. ----------------------------------
  120. oo = OperatorOverride(name=zhang, age=10)
  121. oo = OperatorOverride(name=zhang, age=110)
  122. ----------------------------------
  123. ----------------------------------
  124. oo = OperatorOverride(name=zhang, age=110)
  125. oo = OperatorOverride(name=zhang, age=120)
  126. ----------------------------------
  127. ----------------------------------
  128. oo = OperatorOverride(name=zhang, age=120)
  129. oo = OperatorOverride(name=zhang, age=163)
  130. ----------------------------------
  131. ----------------------------------
  132. true
  133. ----------------------------------
  134. 1
  135. 2
  136. 3
  137. 4
  138. 5
  139. 6
  140. 7
  141. 8
  142. 9
  143. 10
  144. 11
  145. 12
  146. 13
  147. 14
  148. 15

发表评论

表情:
评论列表 (有 0 条评论,81人围观)

还没有评论,来说两句吧...

相关阅读

    相关 C++学习_运算符重载

    运算符重载 1.概念:赋予已经存在的,允许重载的运算符新的含义。 2.不允许重载的运算符: ‘.’ 成员选择符 ‘::’域解析操作符 ‘?:’条件操作符