1、尾递归优化
尾递归:函数在调用自己之后没有再执行其他任何操作就是尾递归
尾递归优化的原理就是将递归转换成迭代,避免栈溢出
-
将递归转成尾递归步骤:
- 将递归修改成尾递归
- 加上
tailrec
关键字
迭代和递归对比
优点 | 缺点 | |
---|---|---|
迭代 | 内存开销小 | 需抽象出数学模型 |
递归 | 逻辑简单易实现 | 内存开销大,容易栈溢出 |
/**
* 1、用迭代的方式求 1 到 n 的和
*/
fun sum0(n: Int): Int {
var result = 0
var temp = n
while (temp > 0) {
result += temp
temp--
}
return result
}
/**
* 2、用递归方式求 1 到 n 的和
*/
fun sum1(n: Int): Int {
return if (n == 1) {
1
} else {
n + sum1(n - 1)
}
}
/**
* 3、尾递归优化后求 1 到 n 的和
*/
tailrec fun sum2(n: Int, result: Int = 0): Int {
return if (n == 1) {
result + 1
} else {
sum2(n - 1, result + n)
}
}
fun main() {
println(sum0(10)) //55
println(sum1(10)) //55
println(sum0(100000)) //705082704
//println(sum1(100000)) //java.lang.StackOverflowError
//尾递归优化后调用
println(sum2(100000)) //705082704
}
2、运算符重载
kotlin 中每个运算符都对应于一个方法
-
运算符重载即重写对应的方法,步骤如下:
- 找到运算符对应的函数
- 在函数前面加上
operator
关键字 - 不关心参数和返回值
-
运算符对应的方法,可以通过如下两个方式查找:
- 官网
(kotlinlang.org)-> LEARN -> Reference -> Other -> Operator overloading
- 在开发工具里面按住
control/command
左键点击运算符会跳转到其对应的方法去
- 官网
class Dog {
var name = "包子"
var age = 10
operator fun plus(dog: Dog): Dog {
this.age += dog.age
return this
}
operator fun plus(age: Int): Dog {
this.age += age
return this
}
operator fun plus(name: String): Int {
this.name = name
return this.age
}
override fun toString(): String {
return "[name=$name, age=$age]"
}
}
fun main() {
val dog1 = Dog()
val dog2 = Dog()
println(dog1.toString()) //[name=包子, age=10]
println(dog2.toString()) //[name=包子, age=10]
val dog3 = dog1 + dog2
println(dog3.toString()) //[name=包子, age=20]
val dog4 = dog1 + 30
println(dog4.toString()) //[name=包子, age=50]
val dog5 = dog1 + "饺子"
println(dog5) //50
}
3、中缀表达式
- 方法前面加上
infix
关键字 - 必须是成员函数或者扩展函数
- 函数必须只有一个参数
- 参数不能是可变参数或者默认参数
class Person(var name: String) {
infix fun sayHelloTo(name: String) {
println("${this.name} say hello to $name")
}
}
fun main() {
val p = Person("ZhangSan")
p.sayHelloTo("LiSi") // ZhangSan say hello to LiSi
p sayHelloTo "LiSi" // ZhangSan say hello to LiSi
val pair = 12 to 20 // Pair(10, 20)
println(pair)
val range = 1..5
println(range)
val range2 = 1 until 5
println(range2)
}
4、委托模式(by)
- 委托模式通过关键字
by
来实现 - 委托模式分为:类委托 和 属性委托
interface WashPower {
fun wash()
}
class BigHeadSon : WashPower {
override fun wash() {
println("大头儿子 -> 开始洗碗了")
}
}
class SmallHeadSon : WashPower {
override fun wash() {
println("小头儿子 -> 开始洗碗了")
}
}
/**
* 1、委托实现1:只能委托给大头儿子
*/
class SmallHeadFather : WashPower by BigHeadSon()
/**
* 2、委托实现2:委托给有洗碗能力的人
*/
class SmallHeadFather2(washPower: WashPower) : WashPower by washPower
/**
* 3、委托加强:在委托前后添加自己的功能
*/
class SmallHeadFather3(private val washPower: WashPower) : WashPower by washPower {
override fun wash() {
println("支付1块洗碗的钱")
washPower.wash()
println("很棒,洗的真干净")
}
}
/**
* 4、属性委托:将属性的 get 和 set 委托给其他对象
* 这里手动实例化了一个 Wife 对象,也可以通过构造函数传递过来
*/
class Husband {
var salary: Int by Wife()
}
/*
class Husband2(wife: Wife) {
var salary: Int by wife
}
*/
class Wife {
var husbandSalary = 0
var selfSalary = 0
// 丈夫取工资
operator fun getValue(husband: Husband, property: KProperty<*>): Int {
return husbandSalary
}
// 丈夫存工资:小于 50 直接全部没收;大于 50 存 50,剩余的没收
operator fun setValue(husband: Husband, property: KProperty<*>, i: Int) {
husbandSalary += if (i > 50) 50 else 0
selfSalary += if (i > 50) i - 50 else i
}
}
fun main() {
val smallHeadFather = SmallHeadFather()
smallHeadFather.wash()
// 大头儿子开始洗碗了
val bigHeadSon = BigHeadSon()
val smallHeadSon = SmallHeadSon()
val smallHeadFather2_0 = SmallHeadFather2(bigHeadSon)
smallHeadFather2_0.wash()
// 大头儿子开始洗碗了
val smallHeadFather2_1 = SmallHeadFather2(smallHeadSon)
smallHeadFather2_1.wash()
// 小头儿子开始洗碗了
val smallHeadFather3 = SmallHeadFather3(bigHeadSon)
smallHeadFather3.wash()
// 支付1块洗碗的钱
// 大头儿子 -> 开始洗碗了
// 很棒,洗的真干净
val husband = Husband()
husband.salary = 100;
println(husband.salary)
// 50
}
5、延迟 lazy 和 lateinit
by lazy | lateinit |
---|---|
1、必须是 val 不可变的 |
1、必须是 var 可变的 |
2、知道具体的值,用到的时候才加载 | 2、不知道具体的值,用到的时候再赋值 |
3、可以单独存在,也可以是成员变量 | 3、可以单独存在,也可以是成员变量 |
4、返回值是最后一行 | |
5、是线程安全的 |
val lazyProp: String by lazy { "张三" }
class LazyLoad {
val lazyProp: String by lazy {
println("惰性加载初始化")
"李四"
}
}
lateinit var lateInitProp: String
class LateInitLoad {
lateinit var lateInitProp: String
}
fun main() {
println(lazyProp)
// 张三
val lazyLoad = LazyLoad()
println(lazyLoad.lazyProp)
// 惰性加载初始化
// 李四
println(lazyLoad.lazyProp)
// 李四
// println(lateInitProp)
// 未赋值不能使用,如果使用会抛出 kotlin.UninitializedPropertyAccessException
lateInitProp = "单独的 lateinit 属性"
println(lateInitProp)
// 单独的 lateinit 属性
val lateInitLoad = LateInitLoad()
lateInitLoad.lateInitProp = "类成员 lateinit 属性"
println(lateInitLoad.lateInitProp)
// 类成员 lateinit 属性
}
6、扩展函数
- 不改变已有类的情况下,为类添加新的函数
- 主要用来替代
java
里面的util
类 - 父类的扩展函数,子类可以调用,但是不能重写
fun String?.myIsEmpty(): Boolean {
return this == null || this.length == 0
}
open class Father
class Son : Father()
fun Father.sayHello() {
println("Father's sayHello")
}
fun main() {
var str: String? = null
println(str.myIsEmpty())
// true
str = "kotlin"
println(str.myIsEmpty())
// false
val father = Father()
father.sayHello()
// Father's sayHello
val son = Son()
son.sayHello()
// Father's sayHello
}
7、Object 单例
- 所有字段都是
private static
的 - 所有的方法都是
public final
的,非static
的 - 默认会创建一个当前类
INSTANCE
对象,并通过静态代码块初始化 - 字段和方法都是通过
INSTANCE
对象来访问 - 适用于字段不多的情况下
object Single {
var prop = "Single"
fun sayHello() {
println("Single hello")
}
}
fun main() {
//val single = Single() // 不能创建对象
println(Single.prop) // Single
Single.sayHello() // Single hello
}
8、伴生对象
伴生对象 companion object
:
-
companion object
内部的成员通过类名调用,外部的成员通过实例对象调用 -
companion object
外部的都是普通的成员变量和方法 -
companion object
内部的变量是private static
的,方法是public final
的 -
companion object
会生成一个public static final class Companion
内部类,并且构造函数是私有的 - 外部类会初始化一个
public static final CompanionObject.Companion Companion
对象 - 外部类通过
Companion
对象去调用companion object
内的成员
class CompanionObject {
var prop = "Normal prop"
fun hello() {
println("Normal hello")
}
companion object {
var staticProp = "Static prop"
fun staticHello() {
println("Static hello")
}
}
}
fun main() {
val companionObject = CompanionObject()
println(companionObject.prop) // Normal prop
companionObject.hello() // Normal hello
println(CompanionObject.staticProp) // Static prop
CompanionObject.staticHello() // Static hello
}
9、kotlin 懒汉单例
- 私有化构造函数
- 使用伴生对象定义私有静态类对象
- 使用
by lazy
来懒加载对象
class LazySingle private constructor() {
val prop = "kotlin 懒汉单例属性"
fun sayHello() {
println("hello kotlin 懒汉单例方法")
}
companion object {
// 1、懒加载;2、只初始化一次;3、线程安全
val INSTANCE by lazy { LazySingle() }
}
}
fun main() {
println(LazySingle.INSTANCE.prop)
// kotlin 懒汉单例属性
LazySingle.INSTANCE.sayHello()
// hello kotlin 懒汉单例方法
}