前言
最近开始重新梳理Android知识,作为Android世界的头等公民,Kotlin现在也越来越受开发者们的重视,很多大厂都将掌握Kotlin作为面试的加分项,因此,本人也开始了自己的Kotlin学习之旅。
Kotlin和Java两者的关系不一般,在学习过程中应该慢慢体会两者的差异,将其优缺点进行对比,接下来几篇博客将会对网上的学习教程进行简单的梳理,加深印象。
包声明
代码文件的开头一般为包的声明,与Java不同,Kotlin源文件不需要相匹配的目录和包,源文件可以放在任何文件目录。如果没有指定包,默认为default
包。默认会有多个包导入到每个Kotlin文件中。
变量声明
可变变量 var
var <标识符> : <类型> = <初始化值>
不可变变量 val
val <标识符> : <类型> = <初始化值>
- 在IDEA中变量标识符通常会加上下划线,如 var a: Int = 1。
- 常量与变量都可以没有初始化值,但是在引用前必须初始化,否则编译时会报错,在没有初始值的情况下类型不能省略;
- 编译器支持自动类型判断,即声明时可以不指定类型,由编译器判断。
//打印a的类型
println(a::class)
println(a::class.java)
在Java中也分可变与不可变(final)。在Kotlin中,更简洁的、更常用的场景是:只要可能,尽量在Kotlin中首选使用
val
不变值。因为事实上在程序中大部分地方使用不可变的变量,可带来很多益处,如:可预测的行为和线程安全。
NULL检查机制
与Java不同,Kotlin的空安全设计对于声明可为空的参数(包括常/变量、函数参数、返回值等),在使用时必须要进行空判断处理,否则编译时会报错。类型后面加?表示可为空。
用if语句判断是否为空
字段后加!!会向Java一样抛出空异常
字段后加?可不做处理返回null,配合?:可做空判断处理(当c为空时值为多少)
// 不做处理返回null
val a = c?.toInt()
// c为空返回-1
val a = c?.toInt() ?: -1
字符串模板
与PHP相似,可以使用$符号
var a = 1
// 模板中的简单名称:
val s1 = "a is $a"
a = 2
// 模板中的任意表达式:
val s2 = "${s1.replace("is", "was")}, but now is $a"
函数定义
Kotlin函数定义使用关键字fun,参数格式与Java不同,标识符在前,类型在后。
支持可变长参数函数,变长参数可以用
vararg
关键字进行标识。支持lambda(匿名函数)。
在Kotlin中可以直接使用
=
符号来直接返回一个函数的值。除了表达式的值,有返回值的函数都要求显式使用return
来返回其值。
fun sum(a: Int, b: Int): Int { // Int 参数,返回值 Int
return a + b
}
fun sum(a: Int, b: Int) = a + b
public fun sum(a: Int, b: Int): Int = a + b // public 方法则必须明确写出返回类型
fun printSum(a: Int, b: Int): Unit {
print(a + b)
}
// 如果是返回 Unit类型,则可以省略(对于public方法也是这样):
public fun printSum(a: Int, b: Int) {
print(a + b)
}
fun vars(vararg v:Int){
for(vt in v){
print(vt)
}
}
// 测试
fun main(args: Array<String>) {
vars(1,2,3,4,5) // 输出12345
}
// lambda表达式
fun main(args: Array<String>) {
val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
println(sumLambda(1,2)) // 输出 3
}
有关函数=
的写法我们来看一个例子:
// 思考,这两种写法有何不同?
val sum = fun(a:Int, b:Int) = a+b
val sumf = fun(a:Int, b:Int) = {a+b}
我们可以将其打印出来看看:
println(sum) //(kotlin.Int, kotlin.Int) -> kotlin.Int
println(sumf) //(kotlin.Int, kotlin.Int) -> () -> kotlin.Int
println(sum(1,2)) //3
println(sumf(1,2)) //() -> kotlin.Int
可以看出,sumf
的返回值是函数类型,这点跟Scala是不同的。在Scala中,带不带大括号{}
,意思一样。那我们要怎么得到它的函数值呢?通过sumf(1,2).invoke()
,我们可以等到与sum(1,2)
一样的结果。
类型检测及自动类型转换
我们可以使用 is
或者!is
运算符检测一个表达式是否某类型的一个实例(类似于Java中的instanceof关键字)。
当类型判断为true时,系统会自动进行类型转换,如下面两个例子:
fun getStringLength(obj: Any): Int? {
if (obj is String) {
// 做过类型判断以后,obj会被系统自动转换为String类型
return obj.length
}
// 在离开类型检测分支后,`obj` 仍然是 `Any` 类型
return null
}
fun getStringLength(obj: Any): Int? {
if (obj !is String)
return null
// 在这个分支中, `obj` 的类型会被自动转换为 `String`
return obj.length
}
区间
区间表达式由具有操作符形式..
的 rangeTo 函数辅以 in 和 !in 形成。
区间是为任何可比较类型定义的,但对于整型原生类型,它有一个优化的实现。以下是使用区间的一些示例:
for (i in 1..4) print(i) // 输出“1234”
for (i in 4..1) print(i) // 什么都不输出
if (i in 1..10) { // 等同于 1 <= i && i <= 10
println(i)
}
// 使用 step 指定步长
for (i in 1..4 step 2) print(i) // 输出“13”
for (i in 4 downTo 1 step 2) print(i) // 输出“42”
// 使用 until 函数排除结束元素
for (i in 1 until 10) { // i in [1, 10) 排除了 10
println(i)
}