运算符和表达式

2018-09-26  本文已影响0人  凌寒天下独自舞

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()方法是否存在,如果存在, 则按如下步骤执行:

  1. 如果 plus()方法也存在, Kotlin将会报告错误(调用的目标方法不确定)。
  2. 确保 plusAssign()没有返回值,否则报告错误。
  3. 如果能通过前两步的检查,则转换为执行 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}")
}
上一篇下一篇

猜你喜欢

热点阅读