运算符和表达式
Kotlin 语言提供了一系列功能丰富的运算符,这些运算符包括所有的算术运算符,还包括比较运算符、逻辑运算符、区间运算符和位运算符等。Kotlin 基本支持 Java 的全部运算符(可能有些在写法上存在差异), Kotlin不支持三目运算符(因为 Kotlin可用 if表达式代替三目运算符),Kotlin 的位运算符与 Java 的位运算符也略有区别 。Kotlin的运算符都是以方法形式来实现的,这些运算符都具有特定的符号(如“+”或“*”)和固定的优先级。
与java相同的运算符
单目前缀运算符
单目前缀运算符有+、-、!这三个 。 它们对应的固定方法如表所示:
运算符 | 对应的方法 |
---|---|
+a | a.unaryPlus() |
-a | a.unaryMinus() |
!a | a.not() |
fun main(args: Array<String>) {
var a :Int =10
var b = -a
println(b)
println(a.unaryMinus())
var c=+a
println(c)
println(a.unaryPlus())
var boo = true
var boo1 = !boo
println(boo1)
println(boo.not())
}
从上面的代码可以看出,-a与 a.unaryMinus()的效果是完全一样的;因此,以后读者在查阅 API时发现某个类有 unaryPlus()、unaryMinus()、 not()方法,那就说明可对该类的实例使用单目前缀运算符+、 -、!进行运算。
自加和自减运算符
自加(++)和自减(--)运算符及对应的固定方法如表所示。
运算符 | 对应的方法 |
---|---|
a++ | a.inc() |
a-- | a.dec() |
由于++、--放在变量前后是有区别的,因此自加和自减运算符对应的 inc()和 dec()两个方法还不完全等同于 a++、 a--。
双目运算符
运算符 | 对应的方法 |
---|---|
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 in b | b.contains(a) |
a !in b | !b.minus(a) |
索引访问运算符
运算符 | 对应的方法 |
---|---|
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,...,i_n,b) |
调用运算符
运算符 | 对应的方法 |
---|---|
a() | a.invoke() |
a(b1,...) | a.invoke(b1,...) |
通过上表可以发现调用运算符其实就是省略了 invoke方法名
fun main(args: Array<String>) {
var a :String ="ssss"
//通过反射获取string类的length()方法
val mtd = a.javaClass.getMethod("length")
//使用传统方法,使用 Method 对象的 invoke ()方法
println(mtd.invoke("111"))
//使用调用运算符
println(mtd("111"))
}
广义赋值运算符
运算符 | 对应的方法 |
---|---|
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()方法。对于广义赋值操作,例如 a+= b, 编译器会先判断 plusAssign()方法是否存在,如果存在, 则按如下步骤执行:
- 如果 plus()方法也存在, Kotlin将会报告错误(调用的目标方法不确定)。
- 确保 plusAssign()没有返回值,否则报告错误。
- 如果能通过前两步的检查,则转换为执行 a.plusAssign(b)。
如果 plusAssign()方法不存在,那么 a+=b 将转换为 a=a+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 |
位运算符
Kotlin 也提供了与 Java 功能完全相同的位运算符,但这些位运算符都不是以特殊字符给出的,而是以 infix 函数的形式给出的,因此程序只能用函数名来执行这些位运算符。
Kotlin支持的位运算符同样有如下 7个。
- and(bits): 按位与。当两位同时为 1 时才返回 1。
- or(bits): 按位或。只要有一位为 1,即可返回 1。
- inv(bits):按位非。单目运算符,将操作数的每个位(包括符号位)全部取反 。
- xor(bits): 按位异或。当两位相同时返回 0,不同时返回 1。
- shl(bits: 左移运算符。
- shr(bits): 右移运算符。
- ushr(bits): 无符号右移运算符。
Kotlin 的位运算符只能对 Int和 Long 两种数据类型起作用。
fun main(args: Array<String>) {
println(5 and 9) //将输出 1
println(5 or 9) //将输出 13
println((-5).inv()) //将输出 4
println(5 xor 9) //将输出 12
}
区间运算符
Kotlin 提供了两个区间运算符,即闭区间运算符和半开区间运算符,它们都可以非常方便地构建一种数据结构,这种数据结构可包含特定区间内的所有值。
闭区间运算符
闭区间运算符a..b用于定义一个从a~b (包括a、b边界值)的所有值的区间。 对于闭区间运算符而言, a 不能大于 b, 否则程序运行时将会报错。
半开区间运算符
半开区间运算符 a until b用于定义一个从 a~b (包括 a边界值,但不包含 b边界值)的所有值的区间。半开区间运算符与闭区间运算符类似,a也不能大于 b。
如果 a until b 中边界 a与边界 b 的值相等,就会产生一个空区间,该区间不包含任何值。
反向区间
如果程序希望区间可以从大到小,则可使用 downTo运算符(其实是一个 infix函数),该运算符同样构建一个闭区间。对于a downTo b而言,此时要求 b不能大于a。
区间步长
前面我们见到的所有区间的默认步长都是 1,也就是区间内两个值之间的差值是1。而通 过 step运算符(其实是一个 infix 函数)可以显式指定区间的步长。例如如下程序:
fun main(args: Array<String>) {
//步长为2
for (num in 7 downTo 1 step 2){
println(num)
}
}
运算符重载
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)
}
fun main(args: Array<String>) {
val d = Data(4,10)
//都输出Data(x=-4, y=-10)
println(-d)
println(d.unaryMinus())
println(!d)
println(d.not())
}
重载自加和自减运算符
上面的表中己经给出了自加和自减运算符对应的方法名,因此只要为任意类定义名为 inc()、dec(),且以 operator修饰的方法,程序即可对该类的实例使用++、--运算符。
data class Data(val x: Int, val y: Int) {
//为 Data 类定义一个 inc ()方法
operator fun inc(): Data {
return Data(x+2, y+2)
}
}
//以扩展方法的形式为 Data 类定义 not ()方法
operator fun Data.dec(): Data {
return Data(x-2, y-2)
}
fun main(args: Array<String>) {
var d = Data(4,10)
//输出Data(x=4, y=10)
println(d++)
//输出Data(x=6, y=-12)
println(d)
var d1 = Data(9,20)
//输出Data(x=7, y=18)
println(--d1)
//输出Data(x=7, y=18)
println(d1)
}
重载双目算术运算符
上面的表中己经给出了双目算术运算符对应的方法名 , 因此只要为任意类定义名为 plus()、 minus()、 times()、 div()、 rem()、 rangeTo(),且以 operator修饰的方法,程序即可对该类的实例 使用+、-、*、/、%、..这些运算符。例如:
data class Point(val x: Int, val y: Int) {
//为 Point 类定义一个 minus ()方法
operator fun minus(target: Point): Double {
return Math.hypot((this.x - target.x).toDouble(), (this.y - target.y).toDouble())
}
}
///以扩展方法的形式为 Point 类定义 times ()方法
operator fun Point.times(target: Point): Int {
return Math.abs(this.x - target.x) * Math.abs(this.y - target.y)
}
fun main(args: Array<String>) {
var p1 = Point(4, 10)
var p2 = Point(5, 15)
var distance = p1 - p2
println("p1 与 p2 的距离为:${distance}")
var area = p1 * p2
println("p1 与 p2 围成矩形的面积为: ${area}")
}