Kotlin基础知识
定义变量常量
在Kotlin中,定义变量时有以下几点与java不同:
位置不同:在 Kotlin 中,数据类型要放到变量后面,并且用冒号(:)分隔,这正好和 Java 相反。
变量和常量需要关键字:在 Kotlin 中,定义变量需要用 var 开头,定义常量需要用 val 。
数据类型首字母:在 Kotlin 中,数据类型都以大写字母开头,而在 Java 中,一般只有类、接口等复杂数据类型的名字才采用首字母大写的方式。
如果在定义变量时未进行初始化,就必须指定数据类型,如果在定义变量或者常量时进行了初始化,就可以不指定数据类型,Kotlin编译器会自动根据等号右侧的值推导数据类型。
private var m: Int = 30 // 定义变量 private val n: Int = 20 // 定义常量,值不可改变 private var k = 40 // 自动推导出变量的数据类型 private val a = 10 // 自动推导出常量的数据类型 复制代码
**延迟初始化属性与变量:**一般地,属性声明为非空类型必须在构造函数中初始化。 然而,这经常不方便。例如:属性可以通过依赖注入来初始化, 或者在单元测试的 setup 方法中初始化。 这种情况下,你不能在构造函数内提供一个非空初始器。 但你仍然想在类体中引用该属性时避免空检测。为处理这种情况,你可以用 lateinit
修饰符标记该属性:
lateinit var name: String // 非空属性延迟初始化 复制代码
定义函数
在kotlin中,函数定义使用fun关键字,参数格式为 参数:类型 ,最后函数返回值类型,如下:
fun add(a:Int,b:Int):Int{ return a+b } 复制代码
如果函数没有返回值,可以返回Unit,也可以什么都不返回(省略Unit):
fun printSum(a:Int,b:Int){ println("sum = ${a+b}") } 复制代码
基础数据类型
在 Kotlin 中,所有东西都是对象,在这个意义上讲我们可以在任何变量上调用成员函数与属性。 一些类型可以有特殊的内部表示——例如,数字、字符以及布尔值可以在运行时表示为原生类型值,但是对于用户来说,它们看起来就像普通的类。 在本节中,我们会描述 Kotlin 中使用的基本类型:数字、字符、布尔值、数组与字符串。
数值类型
Kotlin 提供了一组表示数字的内置类型。 对于整数,有四种不同大小的类型,因此值的范围也不同。
类型 | 字节大小(Bytes) | 位大小(Bits) | 最小值 | 最大值 |
---|---|---|---|---|
Byte | 1 | 8 | -128 | 127 |
Short | 2 | 16 | -32768 | 32727 |
Int | 4 | 32 | - 2^31 | 2^31-1 |
Long | 8 | 64 | -2^63 | 2^63-1 |
对于浮点数,Kotlin 提供了 Float
与 Double
类型。Float为单精度,而Double为双精度。
类型 | 大小(比特数) | 有效数字比特数 | 指数比特数 | 十进制位数 |
---|---|---|---|---|
Float | 32 | 24 | 8 | 6-7 |
Double | 64 | 53 | 11 | 15-16 |
对于以小数初始化的变量,编译器会推断为 Double
类型。 如需将一个值显式指定为 Float
类型,请添加 f
或 F
后缀。 如果这样的值包含多于 6~7 位十进制数,那么会将其舍入。
类型转换: java中可以通过隐式类型转换,数值大的类型可以转换成数据小的类型,但是这样往往会丢失精度,在kotlin中由于不同的表示方式,较小类型并不是较大类型的子类型,较小的类型不能隐式转换为较大的类型。 这意味着在不进行显式转换的情况下我们不能把 Byte 型值赋给一个 Int 变量,每种数据类型都有下面的这些方法,可以转化为其它的类型:
toByte(): Byte toShort(): Short toInt(): Int toLong(): Long toFloat(): Float toDouble(): Double toChar(): Char 复制代码
字符类型
在Kotlin语言中,字符类型用Char 表示,不过与java 不同的是,字符不能直接看成是数字(可以通过显示转换char.toInt()),Char 必需是单引号 ' 包含起来的。比如普通字符 '0','a',字符字面值用单引号括起来: '1'。 特殊字符可以用反斜杠转义。 支持这几个转义序列:\t、\b、\n、\r 、 \' 、\" 、\\ 和 $。
fun check(c:Char){ if (c==1){ //编译失败 } } fun check(c:Char){ if (c=='1'){ //编译成功 } } 复制代码
布尔类型
布尔用 Boolean
类型表示,它有两个值:true 与 false。
若需要可空引用布尔会被装箱。
内置的布尔运算有:
||
– 逻辑或&&
– 逻辑与!
- 逻辑非
数组
数组在 Kotlin 中使用 Array
类来表示,它定义了 get
与 set
函数(按照运算符重载约定这会转变为 []
)以及 size
属性,以及一些其他有用的成员函数:
class Array<T> private constructor() { val size: Int operator fun get(index: Int): T operator fun set(index: Int, value: T): Unit operator fun iterator(): Iterator<T> // …… } 复制代码
我们可以使用库函数 arrayOf()
来创建一个数组并传递元素值给它,这样 arrayOf(1, 2, 3)
创建了 array [1, 2, 3]
。 或者,库函数 arrayOfNulls()
可以用于创建一个指定大小的、所有元素都为空的数组。
另一个选项是用接受数组大小以及一个函数参数的 Array
构造函数,用作参数的函数能够返回给定索引的每个元素初始值:
// 创建一个 Array<String> 初始化为 ["0", "1", "4", "9", "16"] val asc = Array(5) { i -> (i * i).toString() } asc.forEach { println(it) } // 使用arrayOf可以定义存储任意值的数组 var arr1 = arrayOf(1, 2, 3, "hello") println(arr1[3]) // 使用 arrayOfNulls 定义固定长度的数组 var arr2 = arrayOfNulls<Int>(10) println(String.format("arr2数组的长度为%d", arr2.size)) println("arr2数组的长度为:".plus(arr2.size)) // 使用 Array 构造器定义数组并初始化每个数组元素的值 var arr3 = Array(10) { i -> (i * i).toString() } for (i in arr3.indices) { println(String.format("数组arr3第%d个元素的值为:%s", (i + 1), arr3[i])) } println(arr3[9]) // 使用 intArrayOf, shortArrayOf 等函数定义指定类型的数组,井初始化数组 var arr4 = intArrayOf(10, 2, 30, 40) for (i in arr4.indices) { println(String.format("arr4[%d]==%d ,", i, arr4[i])) } 复制代码
Kotlin 中数组是不型变的(invariant)。这意味着 Kotlin 不让我们把 Array<String>
赋值给 Array<Any>
,以防止可能的运行时失败
字符串
在Kotlin中,使用String表示字符串类型,有如下两类字符串:
普通字符串 这种字符串类似于 Ja ,可以在字符串中加上转义符,如
\n
,会让转义符后面的字符串换到下 行,这种字符串需要放在双引号中。保留原始格式的字符串(raw string ):这种字符串不能使用转义符,如果字符串中带有格式,如换行,直接写在字符串中即可。这种字符串需要放在3个引号对中
// 普通字符串,和 java 一样 var s1 = "HELLO \nWORLD \n" // 保留源格式字符串,不能使用转义符 var s2 = """ HELLO WORLD ARE YOU OK""".trimMargin() println(s1.plus(s2)) 复制代码
字符串模板
字符串字面值可以包含模板表达式 ,即一些小段代码,会求值并把结果合并到字符串中。 模板表达式以美元符($
)开头,由一个简单的名字构成:
val i = 10 println("i = $i") // 输出“i = 10” 复制代码
Target platform: JVMRunning on kotlin v. 1.5.31
或者用花括号括起来的任意表达式:
val s = "abc" println("$s.length is ${s.length}") // 输出“abc.length is 3” 复制代码
Target platform: JVMRunning on kotlin v. 1.5.31
原始字符串与转义字符串内部都支持模板。 如果你需要在原始字符串中表示字面值 $
字符(它不支持反斜杠转义),你可以用下列语法:
val price = """ ${'$'}9.99 """ 复制代码
控制流:if、when、for、while
if表达式
在Kotlin中,if语句本身就是表达式,有返回值,因此,Kotlin并不需要像Java那样提供三元运算符(condition?then:else)。因为普通的if就胜任这个角色。
// 传统用法 var a = 20 var b = 30 var min = 0 if (a > b) { println("a,b两者更小的数值是1:b=$b") } else { println("a,b两者更小的数值是2:a=$a") } a = 40 b = 30 if (a > b) min = b println("a,b两者更小的数值是3:a=$a,b=$b,min=$min") a = 50 b = 40 // 表达式用法 min = if (a > b) b else a println("a,b两者更小的数值是4:a=$a,b=$b,min=$min") a = 90 b = 100 min = if (a > b) { b //返回值 } else { a // 返回值 } println("a,b两者更小的数值是5:a=$a,b=$b,min=$min") 复制代码
when语句
在Kotlin中,when替换了C语言放个的switch语句。标准的when语句用法如下:
var x = 1 when (x) { 1 -> println("x==1") 2 -> println("x==2") else -> { println("x is neither 1 or 2") println("end") } } 复制代码
使用when语句时,需注意以下几点:
when 语句会根据传入的值(这里是x)寻找第一个满足条件的分支,找到后执行分支的语句。
如果分支中多于 条语旬,要用{...}
满足条件的分支执行后,会自动终止 when 语句的执行,因此,并不需要像 switch句那样每 case 语句都加上 break
when与if一样,既可以作为语句使用,也可以作为表达式使用。如果是后者,when语句的第一个满足条件的分支的最后一个表达式就是when表达式的返回值。
// when 作为表达式时使用 var x = 1 var m = when (x) { 1 -> 20 2 -> 30 else -> 50 } println("m的值是:$m") // 打印结果:m的值是:20 复制代码
如果其他分支都不满足条件将会求值 else 分支。 如果 when 作为一个表达式使用,则必须有 else 分支, 除非编译器能够检测出所有的可能情况都已经覆盖了[例如,对于 枚举(enum)类条目与密封(sealed)类子类型]。如果很多分支需要用相同的方式处理,则可以把多个分支条件放在一起,用逗号分隔:
// 如果符合多个条件,条件之间可用","隔开 when (x) { 1, 2, 3 -> println("符合条件") else -> println("不符合条件") } 复制代码
如果要执行相同代码的条件比较多,或无法枚举,可以使用 in 关键字确定一个范围,代码如下:
//使用 in 关键字 var n = 25 when (n) { in 1..10 -> println("不符合条件") in 11..20 -> println("符合条件") // !in 表示不在这个范围内 !in 30..60 -> println("hello world") else -> println("条件未知") } 复制代码
还可以是检测一个值是(is)或者不是(!is)一个特定类型的值。注意: 由于智能转换,你可以访问该类型的方法与属性而无需任何额外的检测。
fun hasPrefix(x: Any) = when(x) { is String -> x.startsWith("prefix") else -> false } 复制代码
when 也可以用来取代 if-else if链。 如果不提供参数,所有的分支条件都是简单的布尔表达式,而当一个分支的条件为真时则执行该分支:
when { x.isOdd() -> print("x is odd") y.isEven() -> print("y is even") else -> print("x+y is odd.") } 复制代码
when中的分支条件不仅可以是常量,还可以是任意表达式:例如,下面的代码分支条件就是一个函数
// when 中的分支条件不仅可以是常量,还可以是任意表达式.例如,下面的代码分支条件就是个函数. var k = 5 when (k) { getValue(2) -> println("满足条件") getValue(4) -> println("不满足条件") else -> println("条件未知") } private fun getValue(num: Int): Int { return num * num } 复制代码
for循环
Kotlin 中, for 循环可以直接枚举集合中的元素,也可以按集合索引来枚举元素。
var list = arrayListOf(1, 2, 3, 4, 5) // 下面的语法是使用迭代器( iterator )枚举集合中的所有元素。 for (i in list) println("for 循环使用迭代器打印集合信息:$i") var arr = intArrayOf(6, 7, 8, 9, 10) for (i: Int in arr) println("for 循环使用迭代器打印数组信息:$i") // 使用索引枚举数组中的元素值。 for (i in list.indices) { println("使用索引值枚举元素值list[$i]=${list[i]}") } // 也可以简写为下面这样 for ((index, value) in list.withIndex()) println("使用简写方式索引值枚举元素值list[$index]=$value") 复制代码
while循环
Kotlin 中的 while 循环和 Java 中的 while 循环是一样的,也分为 while 、do ... while
var i = 0 while (i++ < 10) println("while 循环,i = $i") do { if (i % 3 == 0) println("do while 循环 i = $i") if (i == 6) continue println(i) if (i == 5) break } while (--i > 0) 复制代码
在do ... while 循环中使用了 continue、 break ,这两个语句在 for 循环中同样可以使用。continue 是为了忽略当前循环 continue 后面的所有语旬,继续从下一次循环开始。 break 是为了终结当前循环,并跳出循环。这一点和Java 完全一样。
作者:jameschen
链接:https://juejin.cn/post/7023224706786394148