kotlin运算符和表达式

Kotlin与Java相同的运算符

Kotlin 使用 if 表达式代替了三目运算符

Kotlin 的运算符都是以方法形式来实现的,这些运算符都具有特定的符号(如“+”或“*”)和固定的优先级,各种运算符对应的方法名都是固定的,我们只要为某类型提供了特定名称(比如双目+运算符对应的方法名为 plus )的方法,成员方法或扩展方法都可以,接下来就可以对该类型的对象使用用“+”进行运算

单目前缀运算符

var a = 5
var b = false
运算符 对应的方法
+a a.unaryPlus()
-a a.unaryMinus()
!b b.not()

自加和自减运算符

运算符 对应的方法
a++ a.inc()
a-- a.dec()

a++和++a不同,简单来说:
a++是使用的a后,再对a进行加1
++a是先把a加1,然后再使用a

例子:

var i = 10
i = i++;
//此时i=10,首先i++的取值结果为临时变量temp=10,然后i自增,i=11,最后赋值,i=10

双目算术运算符

运算符 对应的方法
a+b a.plus(b)
a-b a.minus(b)
a*b a.times(b)
a/b a.div(b)
a%b a.rem(b)
a..b a.rangeTo(b)

in 和!in 运算符

a和b都是String类型,或者a是数组或集合,b是数组或集合对应的类型

运算符 对应的方法
a in b a.contains(b)
a !in b !a.contains(b)

索引访问运算符

String 类提供了get(index)方法,而数组和集合提供了get(index)方法和set(index,val)方法

运算符 对应的方法
a[i] a.get(i)
a[i] = b a.set(i,b)

调用运算符

运算符 对应的方法
a() a.invoke()
a(b) a.invoke(b)
a(b1,b2) a.invoke(b1,b2)

调用运算符其实就是省略了 invoke 方法名

//使用反射获取 String 类的 length()方法
val method = Class.forName("java.lang.String").getMethod("length")
//使用传统方法,使用 Method 对象的 invoke()方法
Log.d(TAG, "onCreate: ${method.invoke("java")}")

广义赋值运算符

运算符 对应的方法
a+=b a.plusAssign(b)
a-=b a.minusAssign(b)
a*=b a.timesAssign(b)
a/=b a.divAssign(b)
a%=b a.remAssign(b)

a+=b,实际上相当于a=a+b,因此在程序中进a+=b运算时,往往并不需要a要有plusAssign()方法,如果plusAssign()方法不存在,那么 a+=b 将转换为 a=a+b 代码,如果存在,则按如下步骤执行

  1. 如果 plus()方法也存在, Kotlin 会报告错误(调用的目标方法不确定)
  2. 确保plusAssign()没有返回值,否则报告错误(Kotlin 的赋值运算不是表达式,因此不需要返回值)
  3. 如果能通过前两步的检查,则转换为执行a.plusAssign(b)

相等与不等运算符

运算符 对应的方法
a == b a?.equals(b) ?: (b === null)
a != b !a?.equals(b) ?: (b === null)

Kotlin 的“==“不再比较两个变量是否引用同一个对象,“==”和”equals()“比较基本是等义的,只不过“==”比较是空指针安全的

Java 提供的“==”和“!=”在 Kotlin 中则由“===”和“!==”代替了,这才是判断两个变量是否指向同一个对象的方法

比较运算符

运算符 对应的方法
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()方法来实现的,而该方法是Comparable 接口中定义的方法,因此原来 Java 类中支持使用 compareTo()方法比较大小的对象,都可使用比较运算符进行计算

var date1 = Date()
var date2 = Date (System.currentTimeMillis () - 1000)
println(date1 > date2) // 输出 true
println(date1.compareTo(date2) > 0) // 输出 true

String 比较大小的规则是按字符的编号大小进行比较的,先比较两个字符串的首字母,如果首字母相同,再比较第二个字母……依此类推

位运算符

Kotlin 的位运算符只能对 Int 和 Long 两种数据类型起作用

Kotlin 也提供了与 Java 功能完全相同的位运算符,但这些位运算符都不是以特殊字符给出的,而是以 infix 函数的形式给出的

位运算符 说明
and(bits) 按位与,当两位同时为1时才返回1
or(bits) 按位或,只要有一位为1即可返回1
inv(bits) 按位非,单目运算符,将操作数的每个位(包括符号位)全部取反
xor(bits) 按位异或,当两位相同时返回0,不同时返回1
shl(bits) 左移运算符
shr(bits) 右移运算符
ushr(bits) 无符号右移运算符

(-5).inv (),-5的反码:


image-20211020153141668.png

5 xor 9,5和9的异或:


image-20211020153430937.png

左移运算符是将操作数的二进制码整体左移指定位数,左移后右边空出来的位以0填充

-5 shl 2,-5左移2位:


image-20211020153656353.png

右移运算符有两个: shr和ushr,对于shr 运算符而言,第一个操作数的二进制码右移指定位数后 左边空出来的位以原来的符号位填充,ushr 是无符号右移运算符,操作数的二进制码右移指定位数后,左边空出来位总是0填充

-5 shr 2,-5右移2位:


image-20211020154109449.png

-5 shr 2,-5无符号右移2位:


image-20211020154144978.png

注意:

  1. 对于 Int 类型的整数移位a shr b,当b>=32 时,系统先用 b对32求余(因为 Int 类型只有32 位)得到的结果才是真正移位的位数
  2. 对于 Long 类型的整数移位a shr b,当b>=64 时,系统先用 b对64求余(因为 Long 类型只有64位)得到的结果才是真正移位的位数
  3. 只要被移位的二进制码没有发生有效住的数字丢失,左移n位就相当于乘以2的n次方,右移n位就相当于除以2的n次方
  4. 在进行移位运算时,只是得到了一个新的运算结果,而原来的操作数本身是不会改变的

区间运算符

闭区间运算符

闭区间运算符 a..b 于定义一个从ab(包括ab边界值)的所有值的区间,对于闭区间运算符而言, a不能大于b,否则程序运行时将会报错

var range = 2..6
//该区间包含2~6的所有数值,也就是2、3、4、5、6
for (i in range){
    Log.d(TAG, "onCreate: $i")
}

半开区间运算符

半开区间运算符a until b用于定义一个从a ~ b(包括a边界值,但不包含b边界值)的所有值的区间,a也不能大于b

var array = arrayOf(3, 2, 9, 5)
for (i in 0 until array.size){
    Log.d(TAG, "onCreate: ${array[i]}")
}

如果a until b中边界a与边界b值相等,就会产生一个空区间,该区间不包含任何值;如果a..b中边界 a与边界b值相等,就会产生一个只包含一个值的区间,该区间只包含一个边界值

反向区间

如果希望区间可以从大到小,可使用 downTo 运算符(其实是 infix 函数),该运算符同样构建一个闭区间,对于a downTo b而言,此时要求b不能大于a,和..一样,包含两个边界

var range = 6 downTo 2
for (i in range){
    Log.d(TAG, "onCreate: $i")
}

区间步长

区间的默认步长都是1,通过step运算符(其实是 infix 函数)可以显式指定区间的步长

for (i in 6 downTo 2 step 2){
    Log.d(TAG, "onCreate: $i")
}

运算符重载

Kotlin 运算符都是靠特定名称的方法支撑的,因此只要重载这些名称的方法,我们就可以为任意类添加这些运算符,重载运算符的方法需要用 operator 修饰符进行标记

重载单目前缀运算符

只要为任意类定义名为 unaryPlus()、unaryMinus()、not(),且以 operator 修饰的方法,程序即可对该类的实例使用+、-、!单目前缀运算符

data class Data(val x: Int, val y: Int) {
    //为Data类定义一个unaryMinus()方法
    operator fun unaryMinus(): Data {
        return Data(-x, -y)
    }
}

//以扩展方法的形式为Data类定义not()方法
operator fun Data.not(): Data {
    return Data(-x, -y)
}
......

//使用重载的单目前缀运算符
private fun test(){
    var data = Data(2, 4)
    Log.d(TAG, "test: ${!data}")
    Log.d(TAG, "test: ${-data}")
}

重载自加和自减运算符

++、--放在变量前面和后面的差异 ,与Java语言中++、--放在变量前面和后面的差异完全一样

data class Data(val x: Int, val y: Int) {
    //为Data类定义一个inc()方法
    operator fun inc() : Data {
        return Data(x + 1, y + 1)
    }
}

//以扩展方法的形式为Data类定义dec()方法
operator fun Data.dec(): Data {
    return Data(x - 1, y - 1)
}
......

//使用重载的自加和自减运算符
private fun test(){
    var data = Data(2, 4)
    Log.d(TAG, "test: ${data++}")
    Log.d(TAG, "test: ${--data}")
}

重载双目算术运算符

data class Point(val x: Int, val y: Int) {
    //为Point类定义一个minus()方法,计算两个 Point 之间的距离
    operator fun minus(target: Point): Double {
        return hypot((this.x - target.x).toDouble(), (this.y - target.y).toDouble())
    }
}

//以扩展方法的形式为Point类定义times()方法,计算两个 Point 所围成矩形的面积
operator fun Point.times(target: Point): Int {
    return abs(this.x - target.x) * abs(this.y - target.y)
}

......
private fun test() {
    var p1 = Point(4,10)
    var p2 = Point (5, 15)
    var distance = p1 - p2
    var area = p1 * p2
    Log.d(TAG, "test: ${distance}")
    Log.d(TAG, "test: ${area}")
}

你可能感兴趣的:(kotlin运算符和表达式)