培训的目的
怎么在已有项目中快速上手kotlin
一、怎么在已有项目中配置kotlin
二、基本语法
2.1 包定义
Kotlin 中的代码可以组织成多个包。一个文件可以包含多个类或函数,每个文件也可以有自己的包定义。包定义的语法如下:
// 文件 MyFile.kt 中的包定义
package com.benben.demo.bean
// 动态列表
class Dynamic
// 动态详情
class DynamicDetails
2.2 类
2.2.1 定义:
2.2.1.1 方式一
class Person {
var name: String = ""
var age: Int = 0
fun sayHello() {
println("Hello, my name is $name and I am $age years old.")
}
}
在上面的示例中,我们定义了一个名为 Person 的类,它有两个属性 name 和 age,以及一个方法 sayHello()。
在 Kotlin 中,类和属性默认都是 public 可见性,方法默认是 public 可见性且 final 类型(即不能被子类重写),可以使用 open 关键字来允许子类重写。
2.2.1.2 方法二
class Person {
var name: String = ""
var age: Int = 0
constructor(name: String, age: Int) {
this.name = name
this.age = age
}
// ...
}
class Person(var name: String = "",
var age: Int = 0 )
类的构造函数可以使用 constructor 关键字来定义,也可以直接在类名后面加上参数列表来定义。例如:
2.2.2 分类
2.2.2.1 普通类(normal class):定义类时不使用 open 关键字,不能被继承,也没有子类。是最基本的类定义形式。
class Person {
var name: String = ""
var age: Int = 0
fun sayHello() {
println("Hello, my name is $name and I am $age years old.")
}
}
2.2.2.2. 抽象类(abstract class):定义类时使用 abstract 关键字,不能被实例化,只能被子类继承并实现抽象方法或属性。
abstract class Person {
var name: String = ""
var age: Int = 0
fun sayHello() {
println("Hello, my name is $name and I am $age years old.")
}
}
2.2.2.3. 接口(interface):定义类时使用 interface 关键字,不能被实例化,只能被类实现。接口可以包含抽象方法、常量和默认实现的方法。
interface Person {
fun sayHello()
}
2.2.2.4. 内部类(inner class):在类中定义的类,可以访问外部类的成员变量和方法。
class Person {
var name: String = ""
var age: Int = 0
fun sayHello() {
println("Hello, my name is $name and I am $age years old.")
}
}
2.2.2.5. 嵌套类(nested class):在类中定义的类,不能访问外部类的成员变量和方法。
nested class Person {
var name: String = ""
var age: Int = 0
fun sayHello() {
println("Hello, my name is $name and I am $age years old.")
}
}
2.2.2.6 数据类(data class):用于表示仅包含数据的类,Kotlin 自动生成 equals()、hashCode()、toString() 等方法,也可以使用 copy() 方法复制对象。
data Person {
var name: String = ""
var age: Int = 0
fun sayHello() {
println("Hello, my name is $name and I am $age years old.")
}
}
2.2.2.7. 枚举类(enum class):定义了一组有限的值,枚举值之间用逗号分隔。可以使用 when 表达式来匹配枚举值。
enum class Person {
var name: String = ""
var age: Int = 0
fun sayHello() {
println("Hello, my name is $name and I am $age years old.")
}
}
2.3 函数定义
Kotlin 中的函数可以定义在文件中,也可以定义在类中。函数定义的语法如下:
2.3.1 定义
// 定义一个函数
fun sum(a: Int, b: Int): Int {
return a + b
}
// 调用函数
val result = sum(1, 2)
其中,functionName 表示函数名,arg1、arg2 等表示函数参数,Type1、Type2 表示参数的类型,ReturnType 表示函数返回值的类型。
2.3.2 参数
2.3.2.1 默认参数
fun add(a: Int, b: Int): Int {
return a + b
}
在函数定义时,可以给参数指定默认值,当调用该函数时,如果省略了该参数,则使用默认值。
2.3.2.2 可变参数
fun sum(vararg numbers: Int): Int {
var total = 0
for (number in numbers) {
total += number
}
return total
}
println(sum(1, 2, 3, 4, 5)) // 输出:15
在函数定义时,可以使用 vararg 关键字来指定一个参数为可变参数,表示该参数可以接受任意数量的值。例如:
2.3.2.3 高阶参数
fun add(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}
val result = add(2, 3) { a, b -> a + b }
println(result) // 输出:5
在 Kotlin 中,可以将函数作为参数传递给另一个函数,或者从函数中返回另一个函数。这种函数被称为高阶函数
在这个例子中,add() 函数接受三个参数:a、b 和一个函数 operation。在调用 add() 函数时,传递了一个 lambda 表达式作为 operation 参数,表示将 a 和 b 相加。最终返回结果 5。
2.4 流程控制语句
// if 表达式
val result = if (a > b) a else b
// when 表达式
when (x) {
1 -> print("x is 1")
2 -> print("x is 2")
else -> print("x is neither 1 nor 2")
}
三、空安全
Kotlin 对空指针异常进行了处理,它引入了可空类型和非空类型的概念,使得编写代码时更加安全和可靠。
- 可空类型(nullable type):在类型后面加上
?表示该类型可以为null。 - 安全调用操作符(safe call operator):在对象调用方法或属性时,使用
?.来避免出现 NPE。 - Elvis 操作符(elvis operator):使用
?:表示如果对象为null,则返回默认值。 - 非空断言操作符(not-null assertion operator):在对象后面加上
!!表示非空断言,即对象不为null,否则会抛出 NPE 异常。
// 可空类型
var str: String? = null
// 安全调用操作符
val length = str?.length
// Elvis 操作符
val length2 = str?.length ?: 0
// 非空断言操作符
val length3 = str!!.length
使用空安全特性可以让代码更加健壮和安全。但需要注意的是,过度使用 !! 非空断言操作符可能会导致代码出现运行时异常,因此应该谨慎使用。
四、扩展函数与高阶函数
4.1 扩展函数
在 Kotlin 中,扩展函数(Extension Functions)是一种非常方便的语言特性,可以为已有的类添加新的方法,而无需继承或修改该类的源代码。
扩展函数使用 fun 关键字来定义,其第一个参数为接收者类型(Receiver Type),即被扩展的类,使用 . 语法来调用。
// 为 String 类添加一个扩展函数
fun String.customFunction(): String {
return "This is a custom function for String"
}
// 使用扩展函数
val str = "Hello World"
val result = str.customFunction()
通过扩展函数,我们可以为标准库中的类(如 String、List、Int 等)添加自定义的方法,或为我们自己定义的类添加新的方法,从而让代码更加简洁、易读和可维护。但需要注意的是,扩展函数不能访问被扩展类的私有或受保护的成员。
4.2 高阶函数
可以接受函数作为参数或者返回函数作为结果的函数。这种语言特性使得编写具有抽象能力的代码变得更加容易。
// 定义一个接受函数参数的高阶函数
fun calculate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
return operation(x, y)
}
// 定义一个函数类型的变量
val add: (Int, Int) -> Int = { a, b -> a + b }
// 调用高阶函数,并传入函数类型的参数
val result = calculate(10, 5, add)
在上面的代码中,我们定义了一个接受函数参数的高阶函数 calculate,该函数接受两个整数和一个函数类型的参数 operation,并返回 operation 的计算结果。我们又定义了一个函数类型的变量 add,其接受两个整数并返回它们的和。最后,我们调用 calculate 函数并传入 add 作为参数。
高阶函数在函数式编程中应用广泛,可以大大提高代码的抽象能力和可读性,使得代码更加灵活、可重用和可维护。
4.3 常用的一些函数
4.3.1. let
函数是一种作用域函数,它可以在一个对象上执行代码块,然后返回结果。通常用于在代码块中执行一些操作,例如对对象进行非空判断、类型转换、计算等操作。let 函数的用法如下:
object?.let {
// 在 object 不为空的情况下执行以下代码块
// 可以使用 it 代替 object,它是执行代码块的对象
}
val str: String? = "Hello, Kotlin"
str?.let { s ->
// s 不为 null,可以在这里对 s 进行操作
print(s)
}
4.3.2. apply
函数是一种构建函数,它可以在一个对象上执行一系列操作,并返回该对象本身。通常用于在对象构建过程中执行一些操作,例如初始化属性、设置默认值等操作。apply 函数的用法如下:
object.apply {
// 在 object 上执行以下代码块
// 可以使用 this 代替 object,它是执行代码块的对象
}.run {
// apply 函数返回 object,可以继续在其上执行其他操作
}
val person = Person().apply {
name = "Alice"
age = 30
address = "123 Main St"
}
需要注意的是,let 和 apply 函数的区别在于它们的返回值,let 函数返回执行代码块的结果,而 apply 函数返回执行代码块的对象本身。
4.3.3. run
是 Kotlin 标准库中的一种作用域函数,它可以在一个对象上执行代码块,并返回执行结果。常用于在代码块中对对象进行一些操作,例如对对象进行非空判断、类型转换、计算等操作。使用 run 函数可以使代码更加简洁、清晰、安全。
object.run {
// 在 object 上执行以下代码块
// 可以使用 this 代替 object,它是执行代码块的对象
// 返回执行结果
}
val str: String? = "Hello, Kotlin"
val result = str?.run {
// this 不为 null,可以在这里对 this 进行操作
length
}
// result = 13
在上面的示例中,我们使用 run 函数对一个可能为 null 的字符串进行非空判断,并在非空的情况下获取该字符串的长度,最后返回执行结果。
需要注意的是,run 函数与 let 函数类似,都可以帮助开发者编写更加简洁、清晰、安全的代码,同时也可以提高代码的可读性和可维护性。不同之处在于,run 函数可以直接使用 this 访问对象,在代码块中可以省略掉对对象的引用。
4.3.5. with
with 函数是 Kotlin 标准库提供的一个函数,它可以在不使用对象名的情况下,对某个对象进行一系列操作。with 函数的签名如下:
fun <T, R> with(receiver: T, block: T.() -> R): R
其中,receiver 参数表示需要进行操作的对象,block 参数是一个函数类型的参数,表示对 receiver 进行操作的代码块。block 函数类型的接收者是 T,即 receiver 对象本身。
用法如下
with(receiver) {
// 对 receiver 进行一系列操作
}
在代码块内,可以直接使用 receiver 对象的属性和方法,而无需使用对象名进行调用。代码块执行完毕后,会返回最后一个表达式的值。
// 定义一个 Person 类
class Person(var name: String, var age: Int)
// 创建一个 Person 对象
val person = Person("Alice", 25)
// 使用 with 函数修改 Person 对象的属性
with(person) {
name = "Bob"
age = 30
}
// 打印修改后的属性值
println("Name: ${person.name}, Age: ${person.age}") // 输出:Name: Bob, Age: 30
在上面的代码中,我们使用 with 函数对 person 对象进行了一系列操作,包括修改 name 和 age 属性的值。最后,我们打印了修改后的属性值。
总的来说,with 函数可以简化对某个对象的多次操作,并提高代码的可读性。但需要注意的是,with 函数只是提供了一种简化代码的方式,并不会对代码的性能产生显著的影响。
4.3.4 其它函数
also函数:在一个对象上执行一系列操作,返回该对象本身。takeIf函数:根据条件判断是否使用该对象,并返回结果。takeUnless函数:根据条件判断是否不使用该对象,并返回结果。repeat函数:重复执行代码块指定次数。
其它
- Kotlin 官方文档:kotlinlang.org/docs/home.h…
- Kotlin Playground:play.kotlinlang.org/
- Kotlin 专栏:www.jianshu.com/c/5b6c58d6f…
- Kotlin 中文网:www.kotlincn.net/
- Kotlin 实战:www.kotliner.cn/
- Kotlin 手册:www.kotlincn.net/docs/refere…
- Kotlin 学习笔记:www.yiibai.com/kotlin/
- Kotlin 知识库:www.kotlincn.net/kotlin-know…
- Kotlin 官方博客:blog.jetbrains.com/kotlin/
- Kotlin 语言教程:www.runoob.com/kotlin/kotl…