运算符
1、运算符重载
Kotlin支持标准的算数运算表达式,并且Kotlin为这些运算符都内建了对应的函数来表示。
也就是说Kotlin不光支持算数运算符,并且为每种算数运算符都提供一个相应的函数,例如下面的代码:
// plus就是 + 运算对应的函数
val num : Int = 10
println(num +1)
println(num.plus(1))
那么常用的运算符对应函数有哪些呢?
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.mod(b) (deprecated)
a..b a.rangeTo(b)
其他的运算符函数,建议直接查看官网
值得注意的是Kotlin并没有像java那样提供一种特殊符号来表示位运算,取而代之的是一种名为中缀运算符的形式
//java 位运算符(有符号右移)
System.out.println(2>>1);
//Kotlin位运算符(有符号右移)
println(2 shr 1)
位运算符对照表:
shl(bits) – 有符号左移 (相当于 Java’s <<)
shr(bits) – 有符号右移 (相当于 Java’s >>)
ushr(bits) – 无符号右移 (相当于 Java’s >>>)
and(bits) – 按位与
or(bits) – 按位或
xor(bits) – 按位异或
inv(bits) – 按位翻转
2、中缀运算符
前面我们说普通的算数运算符都有对应的函数,中缀运算符也不例外,它是一种特殊的函数,并且我们还可以进行自定义。
满足以下条件的函数就可以使用中缀符调用:
它们是成员函数或者是扩展函数,只有一个参数,使用infix关键词进行标记
扩展函数,到函数里我们再进行讲解。
通过下面的例子,我们自定义一个中缀符:
现在,我们尝试模拟一种坐标的数据类型,并且支持同类型之间添加操作,添加操作结果为对应x,y累加,例如:
//伪代码
Point(1,2) add Point(2,2) 得到 Point(3,4)
开始创建这个类型:
/**
* 坐标数据类
* Created by L on 2017/11/13.
*/
data class Point(val x: Int, val y: Int){
}
数据类有了,为了满足累加功能,我们为它提供一个add()函数
/**
* 累加方法,返回累加后的Potint
*/
fun add(other: Point): Point {
return Point(this.x+ other.x , this.y+other.y)
}
方法添加好后,我们测试也没有问题
val point1 = Point(1, 2)
val point2 = Point(2, 2)
val result = point1.add(point2)
println(result) //打印:Point(3,4)
但是并不是我们想要的中缀运算符的形式调用的,而是通过函数形式调用,那我们还差什么? infix关键词
/**
* 累加方法,返回累加后的Potint
*/
infix fun add(other: Point): Point {
return Point(this.x + other.x, this.y + other.y)
}
为add函数加上infix关键词后,我们再试试
val point1 = Point(1, 2)
val point2 = Point(2, 2)
val result = point1 add point2
println(result) //输出:Point(3,4)
所谓的中缀运算符,只是一种特殊的调用函数的方式,并且满足前面提到的条件即可。
3、空安全
Kotlin在设计上致力消除NullPointerException
Java中的引用数据类型,都是可以设置为null值的;而在Kotlin中是不允许这样做的,如果需要null支持,必须显式的在类型后添加?号(再之前的基本数据类型时我们也提到过),这样做的好处是Kotlin在编译层面上就为我们排除不必要的NullPointerException,例如:
如果你的变量支持null值,那么在你之后使用该变量时,Kotlin都会在编译期提醒你检测空指针问题:
可以看到编译器提醒使用以下两种方案来消除null检测问题
- 添加?号安全检查
该方法会优先检测当前变量是否为null,如果为true返回null值,否则调用后面的变量\函数。
- 添加!!号返回一个非空对象,或者NullPointerException
很显然!!虽然避开了编译器的检查,但运行时依旧会抛出空指针异常。
4、?:操作符
这个比较好理解,看段例子:
//Java代码
String str = null;
String result = str != null ? str : "";
Kotlin实现上面同样功能:
var str: String? = null
var result = str ?: ""
首先,这不是Kotlin中的三目运算符!!!
只是这么个场景实现了和上面三目运算同样的功能罢了;
它只是会优先的检查自身是否不为null,true返回自己,false返回后面的对象;
而三目运算符的两个结果都可以返回除自身之外的对象。
5、Kotlin中有没有三目运算符
很抱歉,没有。
替代品:if表达式
简单来说就是我们的if else语句可以返回值了
var result2 = if (str2 != null) "result=$str2" else ""
更详细的if表达式内容我们在流程控制篇章再聊。
6、安全转换 as?
首先Kotlin中的强制类型转换在语法上与Java不同,假设我们有以下2个Java类:
public class A { }
public class B extends A{ }
B是A的子类,我们通过下面的Kotlin代码将B类对象先向上转型为A类,再强制转换为B类
var a: A = B()
var b: B = a as B
以上代码肯定是没问题的,但是如果a变量本身就是A类对象呢?
var a: A = A()
var b: B = a as B
很明显这时候如果运行代码会抛出ClassCastException:
Kotlin为我们提供了一种安全的转换方案如下:
var a: A = A()
var b: B? = a as? B
我们让B类型支持null后通过as?进行强制转换,如果无法转换不再会抛出ClassCastException,而是返回一个null值,之后的内容我们只需校验b变量为null的情况,从而保证程序的健壮性。
到此,Kotlin中的运算符需要注意的知识点也已总结完毕,如果有遗漏或错误的地方,欢迎评论。