概述
第8章 运算符
Kotlin语言中的运算符(也称操作符)在功能上都与Java、C 和C++极为相似。本章为大家介绍Kotlin语言中一些主要的运算符,包括算术运算符、关系运算符、逻辑运算符、位运算符和其他运算符。
8.1 算术运算符
Kotlin中的算术运算符主要用来组织数值类型数据的算术运算,按照参加运算的操作数的不同可以分为一元运算符和二元运算符。
8.1.1 一元运算符
算术一元运算符一共有3个,分别是-、++和–。具体说明参见表8-1。
表8-1中,-a是对a取反运算,a++或a–是在表达式运算完后,再给a加一或减一。而++a或–a是先给a加一或减一,然后再进行表达式运算。
示例代码如下:
//代码文件:chapter8/src/com/a51work6/ch8.1.1.kt
package com.a51work6
fun main(args: Array) {
var a = 12
println(-a) //a取反,结果输出是-12 ①
var b = a++ ②
println(b) //结果输出是12
b = ++a ③
println(b) //结果输出是14
}
上述代码第①行是-a,是把a变量取反,结果输出是-12。第②行代码是先把a赋值给b变量再加一,即先赋值后++,因此输出结果是12。第③行代码是把a加一,然后把a赋值给b变量,即先++后赋值,因此输出结果是14。
8.1.2 二元运算符
二元运算符包括:+、-、*、/和%,这些运算符对数值类型数据都有效,具体说明参见表8-2。
示例代码如下:
//代码文件:chapter8/src/com/a51work6/ch8.1.2.kt
package com.a51work6
fun main(args: Array) {
//声明一个字符类型变量
val charNum = ‘A’ //'A’字符的Unicode编码是65 ①
// 声明一个整数类型变量
var intResult = charNum.toInt() + 1
println(intResult) //输出66
intResult = intResult - 1
println(intResult) //输出65
intResult = intResult * 2
println(intResult) //输出130
intResult = intResult / 2
println(intResult) //输出65
intResult = intResult + 8
intResult = intResult % 7
println(intResult) //输出3
println("-------")
// 声明一个浮点类型变量
var doubleResult = 10.0
println(doubleResult) //输出10.0
doubleResult = doubleResult - 1
println(doubleResult) //输出9.0
doubleResult = doubleResult * 2
println(doubleResult) //输出18.0
doubleResult = doubleResult / 2
println(doubleResult) //输出9.0
doubleResult = doubleResult + 8
doubleResult = doubleResult % 7
println(doubleResult) //输出3.0
}
上述例子中分别对数值类型数据进行了二元运算,其中代码第①行将字符类型变量charNum与整数类型进行加法运算,参与运算的该字符(‘A’)的Unicode编码为65。其他代码比较简单不再赘述。
8.1.3 算术赋值运算符
算术赋值运算符只是一种简写,一般用于变量自身的变化,具体说明参见表8-3。
示例代码如下:
//代码文件:chapter8/src/com/a51work6/ch8.1.3.kt
package com.a51work6
fun main(args: Array) {
var a = 1
val b = 2
a += b // 相当于 a = a+ b
println(a) //输出结果3
a += b + 3 // 相当于 a = a + b+ 3
println(a) //输出结果8
a -= b // 相当于 a = a- b
println(a) //输出结果6
a *= b // 相当于 a=a*b
println(a) //输出结果12
a /= b // 相当于 a=a/b
println(a) //输出结果6
a %= b // 相当于 a=a%b
println(a) //输出结果0
}
上述例子分别对整型进行了+=、-=、*=、/=和%=运算,具体语句不再赘述。
8.2 关系运算符
关系运算是比较两个表达式大小关系的运算,它的结果是布尔类型数据,即true或false。关系运算符有8种:==、!=、>、<、>=、<=、=和!,具体说明参见表8-4。
默认情况下比较两个对象是指它们的内容相等,而不是比较否是同一个对象。因此两个对象如果需要比较内容相等,需要覆盖equals函数,指定比较规则。问题是比较的规则是什么,例如两个人(Person对象)相等是指什么?是名字?是年龄?问题的关键是需要指定相等的规则,就是要指定比较的是哪些属性相等。
示例代码如下:
//代码文件:chapter8/src/com/a51work6/Person.kt
package com.a51work6
class Person(val name: String, val age: Int) {
//自定义比较规则
override fun equals(other: Any?):Boolean { ①
if (other == null || other !is Person) { ②
return false
}
return (name == other.name
&& age == other.age) ③
}
}
上述代码编写了一个Person类,在代码第①行覆盖了equals函数。代码第②行判断传入的参数对象不是Person类型,如果是则转换为Person,否则返回false。代码第③行是比较,把姓名(name属性)和年龄(age)都同时相等才返回true,否则返回false。这段代码对于读者理解还是有一定难道的,因为很多知识点到目前为止,本书还没有介绍,读者可以先不用关注Person类的实现细节。
调用代码如下:
//代码文件:chapter8/src/com/a51work6/ch8.2.kt
package com.a51work6
import java.util.*
fun main(args: Array) {
val value1 = 1
val value2 = 2
println(value1 == value2) //输出结果为false
println(value1.toDouble() ==1.0) //输出结果为true
println(value1 != value2) //输出结果为true
println(value1 > value2) //输出结果为false
println(value1 < value2) //输出结果为true
println(value1 <= value2) //输出结果为true
val p1 = Person("Tony", 18)
val p2 = Person("Tony", 18)
val p3 = Person("Tom", 20)
val p4 = p3
println(p1 == p2) //输出结果为true ①
println(p1 == p3) //输出结果为false ②
println(p3 === p4) //输出结果为true ③
}
上述代码第①行和第②行都是使用进行比较,比较过程调用了Person
的equals函数,p1和p2姓名和年龄属性相等所以p1和p2相等,而p1与p3不相等。代码第③行使用=比较p3和p4是否指向相同的对象,结果是true。
8.3 逻辑运算符
逻辑运算符是对布尔型变量进行运算,其结果也是布尔型,具体说明参见表8-5。
&&和||都具有短路计算的特点:例如x && y,如果 x 为false,则不计算 y(因为不论 y 为何值,“与”操作的结果都为false);而对于x || y,如果 x 为true,则不计算 y(因为不论 y 为何值,“或”操作的结果都为true)。
这种短路形式的设计,使它们在计算过程中就像电路短路一样采用最优化的计算方式,从而提高效率。
示例代码如下:
//代码文件:chapter8/src/com/a51work6/ch8.3.kt
package com.a51work6
fun main(args: Array) {
val i = 0
var a = 10
var b = 9
if (a > b || i == 1) { ①
println("或运算为 真")
} else {
println("或运算为 假")
}
if (a < b && i == 1) { ②
println("与运算为 真")
} else {
println("与运算为 假")
}
if (a > b || a++ == --b) { ③
println("a = " + a)
println("b = " + b)
}
}
输出结果如下:
或运算为 真
与运算为 假
a =10
b = 9
其中,第①行代码进行短路计算,由于(a > b)是true,后面的表达式(i ==
1)不再计算,输出的结果为真。类似地,第②行代码也进行短路计算,由于(a < b)是false,后面的表达式(i ==1)不再计算,输出的结果为假。
代码第③行中在条件表达中掺杂了++和–运算,由于(a > b)是true,后面的表达式(a++ == --b)不再计算,所以最后是a = 10, b = 9。
8.4 位运算符
位运算是以二进位(bit)为单位进行运算的,操作数和结果都是整型数据。位运算符有如下几个运算符:位反、位与、位或、位异或、有符号右移、左移和无符号右移等,具体说明参见表8-6。
从表8-6所示可见Kotlin的位运算不是采用如+、-、、/等特殊符号,而是使用了函数。而且除了位反inv和无符号右移ushr函数外,其他的位运算函数还可以用中缀运算符表示,中缀运算符本质上是一个函数,该函数只有一个参数。中缀运算符模拟+、-、、/等符号运算符,函数名在中间,省略小括号。例如:
x.and(y) //函数表示
x andy //中缀运算符表示
位运算示例代码:
//代码文件:chapter8/src/com/a51work6/ch8.4.kt
package com.a51work6
fun main(args: Array) {
val a = 0B00110010 //十进制50 ①
val b = 0B01011110 //十进制94 ②
println("a位或b = " + (a or b)) //0B01111110,十进制值126 ③
println("a位与b = " + (a and b)) //0B00010010,十进制值18 ④
println("a位异或b = " + (a xor b)) // 0B01101100,十进制值108 ⑤
println("b按位取反 = " + b.inv()) //十进制值-95 ⑥
println("a有符号右位移2位 = " + (a shr 2)) // 0B00001100,十进制值12 ⑦
println("a有符号右位移1位 = " + a.shr(1)) // 0B00011001,十进制值25 ⑧
println("a无符号右位移2位 = " + a.ushr(2)) // 0B00001100,十进制值12
⑨
println("a左位移2位 = " + (a shl 2)) // 0B11001000,十进制值200 ⑩
println("a左位移1位 = " + (a shl 1)) // 0B01100100,十进制值100 ⑪
val c = -12 ⑫
println("c无符号右位移2位 = " + c.ushr(2)) ⑬
println("c有符号右位移2位 = " + (c shr 2)) ⑭
}
输出结果如下:
a位或b = 126
a位与b = 18
a位异或b = 108
b按位取反 = -95
a有符号右位移2位 = 12
a有符号右位移1位 = 25
a无符号右位移2位 = 12
a左位移2位 = 200
a左位移1位 = 100
c无符号右位移2位 = 1073741821
c有符号右位移2位 = -3
上述代码第①行和第②行分别声明了Int类型变量a和b,为了便于计算数值采用二进制整数表示。
代码第③行中表达式(a or
b)进行位或运算,结果是二进制的0B01111110。a和b按位进行或计算,只要有一个为1,这一位就为1,否则为0。
代码第④行(a and b)是进行位与运算,结果是二进制的0B00010010。a和b按位进行与计算,只有两位全部为1,这一位才为1,否则为0。
代码第⑤行(a xor b)是进行位异或运算,结果是二进制的0B01101100。a和b按位进行异或计算,只有两位相反时这一位才为1,否则为0。
代码第⑥行是调用b.inv()函数按位取反。
代码第⑦行(a shr 2)是进行有符号右位移2位运算,结果是二进制的0B00001100。a的低位被移除掉,由于是正数符号位是0,高位空位用0补。类似代码第⑧行a.shr(1)是进行右位移1位运算,结果是二进制的0B00011001。另外,代码第⑦行(a shr 2)表达式采用的中缀运算符表示,shr是右位移中缀运算符,代码第⑧行a.shl(1)表达式采用的函数调用表示。
代码第⑨行a.ushr(2)是进行无符号右位移2位运算,与代码第⑦行不同的是,无论是否有数符号位,高位空位用0补,所以在正数情况下无符号的右位移和有符号的右位移运算结果是一样的。
代码第⑩行(a shl 2)是进行左位移2位运算,结果是二进制的0B11001000。a的高位被移除掉,低位用0补位。类似代码第⑪行(a shl 1)是进行左位移1位运算,结果是二进制的0B01100100。
代码第⑫声明Int类型负数。无符号的右位移和有符号的右位移在负数情况下差别比较大。代码第⑬行的c.ushr(2)表达式输出结果是1073741821,这是一个如此大的正数,从一个负数变成一个正数,这说明无符号右位移对于负数计算会导致精度的丢失。而有符号右位移对于负数的计算是正确的,见代码第⑭行。
8.5 其他运算符
除了前面介绍的主要运算符,Kotlin还有一些其他运算符。
o 冒号(:)。用于变量或常量类型声明,以及声明继承父类和实现接口。
o 小括号。起到改变表达式运算顺序的作用,它的优先级最高。
o 中括号([])。索引访问运算符号。
o 引用号(.)。调用函数或属性运算符。
o 赋值号(=)。赋值是用等号运算符(=)进行的。
o 可空符(?)。标识一个可空类型。
o 安全调用运算符(?.)。调用非空类型的函数或属性。
o Elvis运算符(?:)。空值合并运算符。
o 非空断言(!!)。断言可空表达式为非空。
o 双冒号(::)。引用类、属性或函数。
o 区间(…)。表示一个范围区间。
o 箭头(->)。用来声明Lambda表达式。
o 展开运算符(*)。将数组传递给可变参数时使用。
除上述运算符位,还有一些鲜为人知的运算符,随着学习的深入用到后再为大家介绍,这里就不再赘述了。
8.6 运算符优先级
在一个表达式计算过程中,运算符的优先级非常重要。表8-7中从上到下从高到低,同一行具有相同的优先级。二元运算符计算顺序从左向右,但是先级15的赋值运算符的计算顺序从右向左的。
运算符优先级大体顺序,从高到低是:算术运算符→位运算符→关系运算符→逻辑运算符→赋值运算符。
本章小结
通过对本章内容的学习,读者可以了解到Kotlin语言的基本运算符,这些运算符包括算术运算符、关系运算符、逻辑运算符、位运算符和其他运算符。最后介绍了Kotlin运算符优先级。
最后
以上就是积极大山为你收集整理的《Kotlin从小白到大牛》第8章:运算符的全部内容,希望文章能够帮你解决《Kotlin从小白到大牛》第8章:运算符所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复