Kotlin系统学习1
- Kotlin是基于JVM的编程语言,由JetBrains开发
- Kotlin可被编译成Java字节码,也可以编译成JavaScript,方便运行在无JVM的设备上
- Kotlin是Android开发的首选语言
- 本节内容
- 变量与常量
- 注释
- 数据类型
- 控制语句
- 操作符与操作符重载
- 函数
变量与常量
- var:变量声明关键字,声明可变变量,必须有初始值,或在init函数中赋值,或用
lateinit声明非基本类型变量 - val:不可修改变量声明关键字,声明不可变变量,必须赋值,或在init函数中赋值,不可用
lateinit声明
// 指定类型并初始化
var a: Int = 10
a = 15 // 重新赋值
// 根据赋值推导类型
var b = 10
b = 15 // 重新赋值
// 不可这么定义变量,必须初始化,或使用lateinit声明后期再初始化
var c: Float // ×
var c: Float? = null // √
var c = 10f // √
lateinit var c: Data // √,lateinit不可以用于基本类型变量
// 不可变的变量定义
val d: Int = 100
d = 200 // ×,不可以重新赋值
d += 200 // ×,不可以重新赋值
Kotlin空安全
Kotlin中可声明一个变量是否可为空,使用可空变量增加程序安全性。
// 可空变量定义
var data: XxxData? = null
// 空安全访问,data为null时,id默认值为-1
val id = data?.id?:-1
Kotlin初始化
在Kotlin中变量要么直接赋初始值,要么设置可空变量默认null,要么声明后期初始化,要么声明延迟初始化,总之声明时必须初始化。
lateinit
后期初始化声明关键字。
- 只可用于var声明的变量。
- 不能用于可空变量。
- 不可用于基本类型变量。例:Int、Float、Double不可以。String、Boolean可以。
- 使用前需赋值否则会报错
UninitializedPropertyAccessException- 检查是否初始化
::tvView.isInitialized
- 检查是否初始化
// 声明
private lateinit var title: TextView
// 使用
if (::title.isInitialized) {
}
lazy { }
延迟初始化,当变量第一次使用时初始化。
- 只可用于val声明的不可变的变量。
private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
const
常量声明关键字,配合val一起使用。
- 只能修饰val,不可修饰var
- 声明:顶层声明、object类中、伴生对象中
const val FILTER = "."
注释
注释包括单行注释、多行注释、类或方法注释。
// 单行注释
/*
多行注释
*/
/**
* 类或方法注释
*/
数据类型
数据类型是一门开发语言的基础构成,也是最基本的语法。
数值类型
严格的数值类型,在传参时,必须相同类型才可以,不同类型需转换,Int->Float必须转换为Float再传。
- 字节类型:Byte,8位。
- 短整型:Short,16位。
- 整形:Int,32位。
- 长整型:Long,64位。
- 浮点型:Float,32位。
- 双精度浮点型:Double,64位。
const val A: Byte = 0
const val B: Short = 1
const val C: Int = 2
const val D: Long = 3L
const val E: Float = 4f
const val F: Double = 5.0
进制数
Kotlin中的进制数包括二进制、十进制、十六进制,不支持八进制。
const val A = 0b00101001 // 二进制
const val B = 125 // 十进制
const val C = 0x0F // 十六进制
字面常量下划线
const val ONE_MILLION = 1_000_000 // 一百万
const val CREDIT_CARD_NUMBER = 1234_5678_9012_3456L // 信用卡号
const val SOCIAL_SECURITY_NUMBER = 888_88_8888L // 社保卡号
const val HEX_BYTES = 0xFF_EC_DC_6E // 十六进制字节
const val BYTES = 0b11001100_10101010_01010101_00100100 // 字节
运算符
比较运算符
- ==:值比较
- ===:地址比较
位运算符
按位操作数值,仅适用于Int、Long类型。
- shl(bits):有符号左移bits位
- shr(bits):有符号右移bits位
- ushr(bits):无符号右移bits位
- and(bits):按位与
- or(bits):按位或
- xor(bits):按位异或
- inv():按位取反
自增自减
- inc():自增1
- dec():自减1
布尔类型
布尔类型使用Boolean关键字声明,值只有true、false。
val flag: Boolean = false
逻辑运算符
- 逻辑与:&&
- 逻辑或:||
- 逻辑非:!
字符型
字符变量使用Char声明,值用''表示,不可直接视为数字,但可显示转为数字。
转义字符
- 制表符:\t
- 换行符:\n
- 退格键(键盘上的Back建):\b
- 键盘上的Enter键:\r
- 反斜杠:\
- 单引号:'
- 双引号:"
- 美元符号:$,不转义在kotlin中表示变量的引用
- 其他的任何字符请使用Unicode转义序列语法。例:'\uFF00'
字符串类型
字符串使用String关键字声明。可通过索引操作字符,也可使用for循环遍历字符。
- 普通字符串:包含转义字符和不包含转义字符的用
"..."括起来字符串 - 三重引号字符串:包含任意字符由
"""..."""括起来的字符串 - 字符串引用使用
$
val str = "string"
val first = str[0]
str.forEach { println(it) }
for (it in str) println(it)
// 字符串定义
val a = "abc"
val b = "$str abc"
val c = "abc\t abc"
val d = """
abc
def ghi
jkl mn opq
rst uvw xyz
""".trimIndent()
字符串操作
字符串查找
fun strOp() {
val str = "Hello World!"
val str1: String? = null
// 获取第一个元素
println("${str.first()}") // H
println("${str1?.firstOrNull()}") // null
println("${str.first { it == 'o' }}") // o
println("${str.first { it == 'x' }}") // 不存在x,抛异常NoSuchElementException
println("${str.firstOrNull { it == 'x' }}") // 不存在x,返回null
// 获取最后一个元素
println("${str.last()}") // !
println("${str1?.lastOrNull()}") // null
println("${str.last { it == 'o' }}") // o
println("${str.lastOrNull { it == 'x' }}") // 不存在x,返回null
println("${str.last { it == 'x' }}") // 不存在x,抛异常NoSuchElementException
// 查找元素
println("${str.find { it == 'o' }}") // 等价于firstOrNull()
println("${str.findLast { it == 'W' }}") // 等价于lastOrNull()
// 查找元素坐标
println("${str.indexOf('o', 0)}") // 4
println("${str.indexOf("World", 0)}") // 6
println("${str.indexOfFirst { it == 'o' }}") // 4
println("${str.indexOfLast { it == 'o' }}") // 7
println("${str.lastIndexOf('o')}") // 7
println("${str.lastIndexOf("World")}") // 6
}
字符串截取
字符串截取可使用方法:substring()、subSequence()。
- Kotlin的substring()直接调用Java的substring()
fun subString() {
val str = "Hello World!"
// 字符串截取
println(str.substring(6)) // World!,从下标6开始,到结束
println(str.substring(0, 4)) // Hell,从下标0开始,取4个元素
println(str.substring(IntRange(0, 4))) // Hello,从下标0开始,取到下标为4的元素,等价于调用substring(0, 4 + 1)
println("${str.subSequence(0, 4)}") // Hell,从下标0开始,取4个元素
println("${str.subSequence(IntRange(0, 4))}") // Hello,从下标0开始,取到下标为4的元素
}
字符串替换
- replace():替换满足条件的字符
fun replaceString() {
val str = "123 o 4 56 o 789"
// 字符串替换
println(str.replace('o', '-')) // 字符替换,123 - 4 56 - 789
println(str.replace("o", ":")) // 字符串替换,123 : 4 56 : 789
println(str.replace(Regex("[0-9]+"), "Hello")) // 正则替换,Hello o Hello Hello o Hello
println(str.replace(Regex("[0-9]+")) { "World" }) // 正则替换,World o World World o World
}
- replaceFirst():替换满足条件的第一个字符
fun replaceFirst() {
val str = "123 o 4 56 o 789"
// 字符串替换
println(str.replaceFirst('o', '-')) // 满足条件第一个字符替换,123 - 4 56 o 789
println(str.replaceFirst("789", "~")) // 满足条件第一个字符串替换,123 o 4 56 o ~
}
- replaceBefore():从第一个匹配字符截取,并在前面追加字符
fun replaceBefore() {
val str = "123 o 4 56 o 789"
// 字符串替换
println(str.replaceBefore('o', "AA")) // AAo 4 56 o 789
println(str.replaceBefore("56", "kotlin")) // kotlin56 o 789
}
- replaceBeforeLast():从最后一个匹配字符截取,并在前面追加字符
fun replaceBeforeLast() {
val str = "123 o 4 56 o 789"
// 字符串替换
println(str.replaceBeforeLast('o', "AA")) // AAo 789
println(str.replaceBeforeLast("56", "kotlin")) // kotlin56 o 789
}
- replaceAfter():截取到第一个匹配的字符,并在其后追加字符
fun replaceAfter() {
val str = "123 o 4 56 o 789"
// 字符串替换
println(str.replaceAfter('o', "AA")) // 123 oAA
println(str.replaceAfter("56", "kotlin")) // 123 o 4 56kotlin
}
- replaceAfterLast():截取到最后一个匹配的字符,并在其后追加字符
fun replaceAfterLast() {
val str = "123 o 4 56 o 789"
// 字符串替换
println(str.replaceAfterLast('o', "AA")) // 123 o 4 56 oAA
println(str.replaceAfterLast("56", "kotlin")) // 123 o 4 56kotlin
}
字符串分割
字符串分割方法:split()、splitToSequence()。
- split():全量分割,返回List,占用大量内存。
- splitToSequence():惰性分割,返回Sequence,几乎不占内存。
- 按规则仅分割第一个元素,后续不执行:
print("aa3b555d9c000j".splitToSequence("\d+".toRegex()).first())
- 按规则仅分割第一个元素,后续不执行:
fun split() {
val str = "123 o 4 56 o 789"
// 字符串分割
println(str.split('o')) // [123 , 4 56 , 789]
println(str.split(" ")) // [123, o, 4, 56, o, 789]
val str2 = "123mine456kotlin789xyz"
val str3 = "abc123mine456kotlin789xyz"
println(str2.split(Regex("[0-9]+"))) // [, mine, kotlin, xyz]
println(str3.split(Regex("[0-9]+"))) // [abc, mine, kotlin, xyz]
println(str2.split(Pattern.compile("[0-9]+"))) // [, mine, kotlin, xyz]
println(str3.split(Pattern.compile("[0-9]+"))) // [abc, mine, kotlin, xyz]
// 单字符分割符
val str4 = "Kotlin,Java,C,C++,Javascript"
str4.splitToSequence(",").forEach { print("$it ") } // Kotlin Java C C++ Javascript
// 多字符分割符
val str5 = "Kotlin,Java-C|C++|Javascript"
str5.splitToSequence(",", "-", "|").forEach { print("$it ") } // Kotlin Java C C++ Javascript
val str6 = "aa3b555d9c000j"
str6.splitToSequence("\d+".toRegex()).forEach { print("$it ") } // aa b d c j
// 仅取前三个元素,不会截取整个字符串,生成前三个后停止
str6.splitToSequence("\d+".toRegex()).take(3).forEach { print("$it ") } // aa b d
str6.splitToSequence("\d+".toRegex()).take(3).toList().forEach { print("$it ") } // aa b d
}
其他操作
fun other() {
val str: String? = "Hello World!"
// 获取字符串长度
println(str?.length) // 12
println(str?.count()) // 12
// 统计重复字符个数
println(str?.count { it == 'l' }) // 3
// 验空
println(str?.isEmpty()) // false,判断length是否为0
println(str?.isNotEmpty()) // true,判断length是否大于0
println(str?.isNullOrEmpty()) // false,判断字符串是否为null,或length是否为0
println(str?.isBlank()) // false,判断length是否为0,判断空格数是否等于当前length
println(str?.isNotBlank()) // true,对isBlank()取反
println(str?.isNullOrBlank()) // false,判断字符串是否为null,或调用isBlank()
// 字符串连接
println(str.plus(" Kotlin")) // Hello World! Kotlin
println(str.plus(123)) // Hello World!123
println(str + true) // Hello World!true
// 字符串反转
println(str.reversed()) // !dlroW olleH
// 判断字符串起始
println(str.startsWith('H')) // true
println(str.startsWith("Hello")) // true
println(str.startsWith("World", 6)) // true,第6个字符是否以World开始
println(str.endsWith('!')) // true
println(str.endsWith("rld!")) // true
}
数组类型
数组由Array表示,创建方式:arrayOf、arrayOfNulls、工厂函数(Array)。
- 原始类型数组
- 字节型数组:ByteArray(2)
- 短整型数组:ShortArray(2)
- 整型数组:IntArray(2)
- 长整型数组:LongArray(2)
- 布尔型数组:BooleanArray(2)
- 字符型数组:CharArray(2)
- 浮点型数组:FloatArray(2)
- 双精度浮点型数组:DoubleArray(2)
// 创建一个数组,参数是一个可变参数的泛型对象
val a = arrayOf("abc", "xyz")
// 创建一个指定数据类型且可以为空元素的给定元素个数的数组
val b = arrayOfNulls<String>(3) // 默认3个值都为null
b[0] = "abc"
b[1] = null
b[2] = "xyz"
// 工厂函数Array()创建数组,它使用数组大小和返回给定其索引的每个数组元素的初始值的函数。
// Array() => 第一个参数表示数组元素的个数,第二个参数则为使用其元素下标组成的表达式
val c = Array(5) { index -> index }
val d = Array(5) { index -> "string $index" }
val e = intArrayOf(0, 1, 2, 3, 4, 5)
val f = charArrayOf('a', 'b', 'c', 'd', '1', '2')
可空类型
可空类型定义格式以String类型为例var a: String? = null,即在变量类型后加?。加了?的var变量才可被赋值为null。
- 可空类型使用方式
- 使用
if...else...判断 - 使用
?.判断
- 使用
- 可空类型操作符
?::可空类型赋默认值!!:强制指定可空对象为非空,当对象为空时抛出空指针异常NullPointerExceptionas?:类型安全转换,as操作符属于强制转换,类型不匹配会抛出类型转换异常,而as?会返回null,而不抛出异常。
var a: String? = null
var b: String = null // ×
// 可空类型使用方式
var a: String? = null
if (a == null) {
} else {
}
val i = a?.length // a为null时,i为null
val i = a?.length?:-1 // a为null时,i为-1
val i = a!!.length // a为null时,抛出空指针异常
print("${"abc" as Int}") // 抛出ClassCastException异常
print("${"abc" as? Int}") // null
控制语句
if语句
kotlin中if语句不仅可以作为条件判断,也可以作为块用于返回值
if (flag) true else false
val a = if (flag) "a" else "A" // a = a 或 a = A
for语句
- for循环提供迭代器用来遍历任何东西
- for循环数组被编译为一个基于索引的循环,不会创建迭代器对象
// 递增[0, 5)
for (i in 0 until 5) {
// i >= 0 && i < 5
// 0、1、2、3、4
println("$i")
}
// 递增[0, 5]
for (i in 0 .. 5) {
// i >= 0 && i <= 5
// 0、1、2、3、4
println("$i")
}
// 递减
for (i in 5 downTo 0) {
// i >= 0 && i < 5
// 5、4、3、2、1、0
println("$i")
}
// 设置步长
for (i in 0 .. 5 step 2) {
// i >= 0 && i <= 5,每次+2
// 0、2、4
println("$i")
}
// 遍历
for (c in "abc_def_ghi") {
println("$c")
}
val values = intArrayOf(0, 1, 2, 3, 4, 5)
for (value in values) {
println("value: $value")
}
for (i in values.indices) {
println("index: $i, value: ${values[i]}")
}
for ((i, value) in values.withIndex()) {
println("index: $i, value: $value")
}
while语句、do...while语句
循环语句,二者区别是后者最少执行一次
// 迭代器遍历
val hybridArray = arrayOf(0, 'a', true, "abc", 1f, 1.0)
val iterator: Iterator<Any> = hybridArray.iterator()
while (iterator.hasNext()) {
println("value: ${iterator.next()}")
}
// while循环求和
var i = 0
var sum = 0
while (i < 10) {
sum += i
i++
}
// do...while循环求和
var i = 0
var sum = 0
do {
sum += i
i++
} while (i < 10)
when语句
分支语句
// 使用方式1:分支匹配
val flag = true // 或flag等于其他值,分支改为对应的匹配规则即可
when (flag) {
true -> {}
false -> {}
}
// 使用方式2:合并分支
val flag = 1
when (flag) {
1, 2, 3, 4 -> {} // 多条分支处理一致时,使用逗号合并分支
else -> {}
}
// 使用方式3:表达式
val flag = 5
when (flag > 3) {
true -> {}
false -> {}
}
// 使用方式4:值是否属于某一集合
val flag = arrayOf(1, 2, 3, 4, 5)
when (3) {
in flag -> {}
!in 7 .. 10 -> {}
else -> {}
}
// 使用方式5:类型判断
val flag = "abc"
when (flag) {
is String -> {} // 或!is String
else -> {}
}
// 使用方式6:无表达式
when {
3 > 5 -> {}
1 is Int -> {}
else -> {}
}
return、break、continue语句
跳转语句。
- return:结束封闭函数或匿名函数返回
- break:终止最近的循环体
- continue:跳至循环的下一个步骤
// return
fun returnFun(flag: Boolean) {
if (!flag) {
return
}
println("flag: $flag")
}
// break
fun breakFun() {
var count = 1
for (i in 0 .. 10) {
count++
if (count > 5) {
break
}
}
print(count)
}
// continue
fun continueFun() {
var x = 0
for (i in 0 .. 10) {
if (i == 5) {
x = i
continue
}
}
print(x)
}
操作符与操作符重载
一元操作符
只有一个操作数
- +:正号,+5 == 5.unaryPlus()
- -:负号,-5 == 5.unaryMinus()
- !:取反,!true == true.not()
- ++:自增
- a++:先计算,后自增
- ++a:先自增,后计算
- --:自减
- a--:先计算,后自减
- --a:先自减,后计算
var a = 10
var b = 10
var c = 10
var d = 10
// a++=10, ++b=11, c--=10, --d=9
println("a++=${a++}, ++b=${++b}, c--=${c--}, --d=${--d}")
// 重载
var a = 10
var b = 10
var c = 10
var d = 10
a.also { a.inc() } // a++
b.inc().also { b = it } // ++b
c.also { c.dec() } // c--
d.dec().also { d = it } // --d
// a++=10, ++b=11, c--=10, --d=9
println("a++=${a}, ++b=${b}, c--=${c}, --d=${d}")
二元操作符
操作数大于等于两个
- +:加法,a+b == a.plus(b)
- -:减法,a-b == a.minus(b)
*:乘法,a*b == a.times(b)- /:除法,a/b == a.div(b)
- %:取余,a%b == a.mod(b) == a.rem(b)
- ..:范围,a..b == a.rangeTo(b)
- +=:加等,a+=b -> a=a+b -> a=a.plus(b)
- -=:减等,a-=b -> a=a-b -> a=a.minus(b)
- =:乘等,a=b -> a=a*b -> a=a.times(b)
- /=:除等,a/=b -> a=a/b -> a=a.div(b)
- %=:余等,a%=b -> a=a%b -> a=a.rem(b)
函数
函数使用fun关键字声明,格式:private fun funName(params: Int, ...): Int { }
- 默认修饰符为
public,还可以使用private仅内部使用 - ()中为参数,参数可有可无
- {}中为函数体,在单函数体作为返回值时可省略大括号
fun funName(): Boolean = true - 无返回值时可省略返回值类型
fun funName(): Unit { }或fun funName() { }
fun funName(a: Int): Int {
return a * a
}
// 或
fun funName(a: Int): Int = a * a
函数参数
- 无参数
- 有参数
- 默认参数,参数有默认值
- 命名参数,传参时显示指定参数名
- 可变参数,参数个数不定,使用vararg修饰变量
fun funName(vararg a: Int) { }- vararg修饰的变量相当于一个固定类型的数组
- 集合作为参数时需使用伸展操作符
*
// 无参数
private fun funName() { }
// 有参数
private fun funName(a: Int, b: Int): Int = a + b
// 默认参数,参数有默认值
private fun funName(a: Int = 1, b: Int = 2): Int = a + b
funName(3, 5) // 使用3、5代替a和b
funName() // 使用函数默认值
// 命名参数,传参时显示指定参数名
private fun funName(a: Int = 1, b: Int = 2): Int = a + b
funName(b = 3) // a使用默认值,b使用命名方式指定为3
// 可变参数,参数个数不定
private fun funName(vararg a: Int) {
// 获取元素
println(a[0]) // 1
println(a.component1()) // 1
// ...1-5对应0-4下标数据
println(a.component5()) // 5
println("${a.map { print(it) }}") // 12345[kotlin.Unit, kotlin.Unit, kotlin.Unit, kotlin.Unit, kotlin.Unit]
println("${a.filter { it % 2 == 0 }}") // [2, 4]
println("${a.sortedBy { it }}") // 按指定字段升序排序[1, 2, 3, 4, 5]
}
funName(1, 2, 3, 4, 5)
// 集合需使用伸展操作符*
val arr = intArrayOf(1, 2, 3, 4, 5)
funName(*arr)
单表达式函数
函数具有返回值并且函数体只有一行。
private fun funName(a: Int, b: Int) = a + b
private fun funName(a: Int, b: Int): Int = a + b