kotlin类与对象

1. 函数

1.1 创建函数

Kotlin函数使用fun关键字声明:

1
2
3
fun 函数名称([函数参数...]): 返回值类型 {
//函数体
}

例如,我们创造一个空类型的返回函数,在java中我们通常使用void函数,在kotlin中我们使用Unit类型:

1
2
3
4
5
6
7
8
9
10
11
//这个函数用于打印一段文本
fun hello(): Unit { //本质上应该是返回Unit类型,这个类型表示空,类似于Java中的void,默认情况下可以省略
println("Hellow,kotlin")
}
//这里同如果是Unit不需要参数返回类型则可以不写,如下
// fun hello(){
// println("Hellow,kotlin")
// }
fun main(){
hello()
}

1725802384956.png

当我们需要一个传入参数的函数的时候,例如:

1
2
3
4
5
6
fun main(){
say("你好")//调用say函数
}
fun say(message: String): Unit{ //在定义函数时,可以将参数写到
println("我说:$message")
}

1725802938676.png

同样我们也可以创建一个字符串常量(变量)将它的传入函数也是一样的:

1
2
3
4
5
6
7
fun main(){
var mess:String = "你好"
say(mess)//调用say函数
}
fun say(message: String): Unit{ //在定义函数时,可以将参数写到
println("我说:$message")
}

这里的结果和上述一样,这里不再提供图片。特别,当我们需要将函数值返回时,可以将函数体后面的Unit改成需要返回的数值类型,下面以整型加法函数举例:

1
2
3
4
5
6
fun main(){
println(add(1, 2))
}
fun add(number1:Int,number2:Int):Int{//特别注意这里不再是和java一样使用Int number1
return number1+number2
}

1725803517958.png

特别的,如果我们在上述函数中想要不传入参数而得到结果,我们在java中常用的方法就是在对应的方法中再写一个重载的相同函数,但是在kotlin中我们可以直接指定他的默认值:

1
2
3
4
5
6
7
8
9
fun main(){
println(add())
println(add(number2 = 2))
println(add(2, 3))

}
fun add(number1:Int=2,number2:Int=1):Int{//我们可以在这里指定未赋值时默认的参数值
return number1+number2
}

1725804418760.png

这里需要注意,函数中定义好的number1,number2类型是常量,不允许在函数体中进行修改,kotlin中还允许函数中定义函数,这种在java等等语言中是不被允许的:

1
2
3
4
5
6
fun outer(){
fun inner(){
}

inner()
}

同时内部函数可以访问外部函数中定义的常量值,但是外部函数不能访问内部函数的值:

1
2
3
4
5
6
fun outer(){
val a = 10;
fun inner(){
println(a)
}
}

1.2 全局变量

在java中,我们通常在一个类中所有的方法前定义一个全局变量,在kotlin中,我们可以设置一个全局变量同时修改它的值和获取方式,这是在java等其他语言中所不被允许的操作:

1
2
3
4
5
6
7
8
9
10
11
12
var str: String = "尊嘟假嘟"
get() = field + field //这里的field表示的值就是当前str的值
set(value) { //这里的value就是给过来的值
println("设置变量的值")
field = value //注意,对于val类型的变量,没有set函数,因为不可变
}

fun main(){
println(str)
str = "你好"
println(str)
}

在这个案例中,在main方法中对str直接打印和赋值时,会自动调用get和set方法:

1725807010030.png

1.3 递归函数

我们前面学习了如何调用函数,实际上函数自己也可以调用自己。

1
2
3
fun test(){
test() //我自己调用自己
}

下面通过一个经典的斐波那契数列来分析这个问题,对于求解斐波那契数列第N个数这类问题,我们也可以使用递归来实现:

1
2
3
4
5
6
7
8
fun main() {
println(fib(5))
}

fun fib(n: Int): Int{
if(n <= 2) return 1 //我们知道前两个一定是1,所以直接返回
return fib(n - 1) + fib(n - 2) //当前fib(n)的结果就是前两个结果之和,直接递归继续找
}

不过,这种函数的效率就非常低了,相比循环来说,使用递归解决斐波那契问题,时间复杂度会呈指数倍增长,且n大于20时基本可以说很卡了(可以想象一下,每一个fib(n)都会分两个出去,实际上这个中间存在大量重复的计算)

那么,有没有办法可以将这种尾部作为返回值进行递归的操作优化一下呢?我们可以使用tailrec关键字来实现:

1
2
3
4
5
6
tailrec fun test(n: Int, sum: Int = 0): Int {
if(n <= 0) return sum //到底时返回累加的结果,出口
return test(n - 1, sum + n) //不断累加
}
fun main() {
println(test(3)) }

实际上在编译之后,会变成这样:

1725870105112.png

运行结果:

1725870159887.png

1.4 库函数

和各大语言一样,kotlin也提供了相比较java更加丰富的库函数:

例如在math库中有着更加丰富的功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import kotlin.math.*    //我们需要使用import来引入某些库,这样才能使用库函数

fun main() {
println(1.0.pow(4.0)) //我们可以使用pow方法直接计算a的b次方
abs(-1); //abs方法可以求绝对值
max(19, 20); //快速取两个数的最大值
min(2, 4); //快速取最小值
sqrt(9.0); //求一个数的算术平方根
sin(PI / 2); //求π/2的正弦值,这里我们可以使用预置的PI进行计算
cos(PI); //求π的余弦值
tan(PI / 4); //求π/4的正切值
asin(1.0); //三角函数的反函数也是有的,这里是求arcsin1的值
acos(1.0);
atan(0.0);
ceil(4.5) //通过使用ceil来向上取整
floor(5.6) //通过使用floor来向下取整
}

1.5 高阶函数与lambda表达式(难)