移动端成长日记
记录成长的点滴
Kotlin基础
类型
- kotlin没有类型的隐式转换,必须显式转换
1
2
3
4
5
6
7
8
9
10
11val b: Byte = 1 // OK, 字面值会静态检测
// val i: Int = b // 错误
val i1: Int = b.toInt() // 使用toInt方法显示转换类型
/* toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double */
// 这种情况可以隐式推导
val l = 1L + 3 // Long + Int => Long - 整数类型:Byte(8), Short(16), Int(32), Long(64)
- 浮点类型:Float(32)(可以加f或者F后缀指定), Double(64)
- 数字字面值常量:十六进制
0xFF
,二进制0b01
- 当初始化一个没有显式指定类型的变量时,编译器会自动推断为足以表示该值的最小类型。
1
2
3var one = 1L // 可以显式指定后缀L表示该类型为long
// 使用下划线表示数字常量更易读
val oneMillion = 1_000_000 - JVM平台的数字表示为原生类型
int
,double
等,例外情况是当创建可空数字引用如Int?
或者使用泛型时。在这些场景中,数字会装箱为Java类Integer
、Double
等,这样就可以使用一些方法如valueOf()
- 默认情况下kotlin中的所有声明都默认是非空的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18fun main() {
// var是可变的,而val是不可变的(类似于const)
val a: Int = 100
// Int后面带问号表示类型为可空的
val boxedA: Int? = a
val anotherBoxedA: Int? = a
val b: Int = 10000
val boxedB: Int? = b
val anotherBoxedB: Int? = b
// "==="用于比较两个对象的引用(JVM没有指针的概念,实际上操作的是引用(同cpp))
// 可空引用的不同的原因在于JVM对-128到127的整数(Integer)应用了内存优化
println(boxedA === anotherBoxedA) // true
println(boxedB === anotherBoxedB) // false
// 虽然引用不同但是它们值相等
println(boxedB == anotherBoxedB) // true
} - 整数(非浮点)除法会自动向下取整
- 位运算
1
2
3
4
5
6
7shl(bits) – 有符号左移
shr(bits) – 有符号右移
ushr(bits) – 无符号右移
and(bits) – 位与
or(bits) – 位或
xor(bits) – 位异或
inv() – 位非 - 区间实例以及区间检测:
a..b
,x in a..b
,x !in a..b
控制流程
- when语句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26when (x) { // 类似于switch
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // 类似于defualt
print("x is neither 1 nor 2")
}
}
// 也可以这么写
when (x) {
// 多种情况
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
// 可以用任意表达式,不只是常量,来作为分支条件
when (x) {
s.toInt() -> print("s encodes x")
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("s does not encode x")
}
// 可以使用`is`来检测是否为特定类型的值
fun hasPrefix(x: Any) = when(x) {
is String -> x.startsWith("prefix")
else -> false
} - for范围语句
1
2
3for (item: Int in ints) {
// ……
}- 提供了迭代器对象
有一个成员函数或者扩展函数iterator()
返回Iterator<>
:
有一个成员函数或者扩展函数next()
有一个成员函数或者扩展函数hasNext()
返回Boolean
。 - 若要在数字范围迭代,则使用区间表达式,如:
1
2
3
4
5
6
7
8
9
10
11fun main() {
// arrayOf创建数组
val array = arrayOf("a", "b", "c")
// indices 是数组类型的一个属性,用于获取数组的索引范围。
// i不需要显式定义
for (i in array.indices) {
println(array[i])
}
}
// 若想反向迭代,则使用downTo
for (i in 4 downTo 1 step 1) print(i)
- 提供了迭代器对象
- 返回,支持label
1
2
3
4
5
6// lambda表达式写法,对于list中的每一个元素,都执行后面的语句
// 其中后跟@的一串字符为label,可以进行对应的跳转
listOf(1, 2, 3, 4, 5).forEach lit@{
if (it == 3) return@lit // 局部返回到该 lambda 表达式的调用者——forEach 循环
print(it)
}- 当要返一个回值的时候,解析器优先选用标签限定的返回
1
return@a 1
- 当要返一个回值的时候,解析器优先选用标签限定的返回
- 异常,Kotlin 中所有异常类继承自
Throwable
类。 每个异常都有消息、堆栈回溯信息以及可选的原因。1
2
3
4
5
6
7
8
9
10fun main() {
throw Exception("Hi There!")
try {
// 一些代码
} catch (e: SomeException) {
// 处理程序
} finally {
// 可选的 finally 块
}
}
包与导入
- 源文件所有内容(无论是类还是函数)都包含在该包内。源文件通常以包声明开头
- kotlin中会默认导入
1
2
3
4
5
6
7
8
9
10
11kotlin.*
kotlin.annotation.*
kotlin.collections.*
kotlin.comparisons.*
kotlin.io.*
kotlin.ranges.*
kotlin.sequences.*
kotlin.text.*
// 如果是JVM会额外导入
java.lang.*
kotlin.jvm.* - 如果出现包名冲突,可以用
as
关键字来消除歧义1
2import org.example.Message // Message 可访问
import org.test.Message as TestMessage // TestMessage 代表“org.test.Message” - 关键字
import
除了导入类以外还可以,导入顶层函数及属性、在对象声明中声明的函数和属性、枚举常量 - 顶层函数及属性(类似于全局函数和变量)
函数
- 如果函数没有返回类型,那么默认返回类型就是Unit,如
1
2
3
4
5
6
7
8// 函数前需要加func关键字
fun printMessage(message: String): Unit {
println(message)
}
// 等价的
fun printMessage(message: String) {
println(message)
} - lambda表达式
1
fun maxOf(a: Int, b: Int) = if (a > b) a else b
- 被替换的方法中某些参数的类型以问号 ? 为后缀。这表示传递给这些参数的实际参数可以为 null
变量
- 自动推导,类似于cpp的auto
1
2
3
4val a: Int = 1 // 立即赋值
val b = 2 // 自动推断出 `Int` 类型
val c: Int // 如果没有初始值类型不能省略
c = 3 // 明确赋值