kotlin let函数(Kotlin的扩展函数知识点)

本文目录
- Kotlin的扩展函数知识点
- 安卓题,用 KOTLIN 函数功能实现2个整数的加减法操作,并举例输出 6-5 的值
- Kotlin的延迟初始化
- kotlin继承
- Kotlin笔记(扩展)
- kotlin入门(3)-数组
- kotlin之构造函数(constructor)
- kotlin 函数怎么返回多个值
Kotlin的扩展函数知识点
一个新特性的出现必然是为了解决之前遗留的开发问题和提升目前开发效率。扩展函数也是如此。
首先来介绍下OOP: 开放封闭原则 。
举个栗子: 当某个三方库的功能无法满足现有业务时需要新增功能时。最简单的做法就是 直接对库源码修改 ,但是这样违反了开放封闭原则:对源码 修改 。
更合理的方案是依靠 扩展 。Kotlin的扩展函数很显然能够优雅的解决这种问题。
首先来看下他的使用:
我们将MutableList叫做接受者(receivers),意思就是这个MutableList接受了这个函数,也就是给这个类扩展了这个函数。
Java中的 this叫做调用者 ,对于普通函数来说就是该函数所属类的实例也就是调用者对象。由于这个函数是属于MutableList的,所以在这个方法体中this也就是指代的MutableList。 通俗的来说 扩展函数体里面的this就是receivers的类型
根据上面定义的扩展函数栗子,来看下这个扩展函数的用法:
还是回到刚刚第二个话题,这次的 是什么 就不是简单的介绍了。之前有篇文章讲解过新技术必然离不开 性能方面 的考虑。因此再来讲解下他是如何实现扩展函数的,我们通过解析他的反编译字节码~~
可以看到该函数会变成一个 静态不可重写 的方法,并且 receiver变成了第一个参数 。扩展函数里的的this就是receiver参数。
看来并没有什么神奇的地方只是将扩展函数变成了一个静态方法而已。所以性能方面是没有影响的
这里首先说明下,扩展函数定义在不同的地方效果也是不一样的。
可以看到上面反编译后的扩展函数就是这种类型,被static,public,final修饰的方法会有这个特征:在 同一个包中是可以共享这个扩展函数 的也就是可以调用到这个扩展函数。其他包里面如果也想使用这个函数就可以import这个包中的这个函数即可。
这时候诡异的事情出现了, 扩展函数无法被调用 。接下来看下对应的扩展函数反编译后的字节码:
可以看到失去了static关键字并且变成了外部类中的方法(和正常的方法没什么区别了),也就是 其他地方调用不到了,只有该类或者该类的子类可以调用 ;如果失去了public关键字,那么将只有该类才能使用这个扩展函数,其子类也无法使用。
前面介绍了扩展函数实现的原理并且看到了扩展函数的作用域信息,接下来分析下扩展函数在哪些场景下会被限制。
首先来回顾下普通的静态函数/变量如何定义,在Kotlin中使用伴生对象类将函数/变量定义在其中,那么该函数/变量就是静态函数/变量了。
和普通函数/变量一样,扩展函数也是一样的定义方式,在伴生对象中定义扩展函数:
这样foo就不需要Son的实例直接可以通过Son的类名进行调用了。
这样似乎看起来没有什么问题,但是当我们 需要扩展三方类的静态函数 时,如果其没有用Kotlin的伴生对象指定静态方法/变量,那么该方案将无法使用,只能用 实例去调用 。
有没有想过这样一种情况:就是这个类扩展的函数名之前在这个类中就已经存在了,那么调用这个方法时,会调用扩展函数还是之前类中定义好的方法。
答案是:之前类中定义的方法、 因此: 成员方法优先级高于扩展函数
当我们在类中使用扩展函数时,在扩展函数体内想要获取当前类的this,而不是默认的扩展函数的receivers的类型的时候,我们可以指定this@类名来指向外部类。
调用者类型是运行时类型,而接受者类型是编译时类型也就是说当扩展被生命为成员函数时具体调用哪个类的扩展方法是由它的运行时类型决定,而具体调用哪个扩展方法是根据其被定义为什么类型也就是编译时可知类型。
还是java中的规则: 重载基于编译时类型,重写基于运行时类型。
所以在编写扩展函数时需要注意
Kotlin的扩展函数是非常好用的,其符合OOP原则,而且还可以扩展很多函数Google的ktx库也是基于这个功能开发了很多好用的方法。
安卓题,用 KOTLIN 函数功能实现2个整数的加减法操作,并举例输出 6-5 的值
在Kotlin中,可以使用函数来实现2个整数的加减法操作。下面是一个示例函数的代码:
fun calc(a: Int, b: Int, operator: String): Int {
return when(operator) {
"+" -》 a + b
"-" -》 a - b
else -》 0
}
}
这个函数接受3个参数:a和b是2个整数,operator是一个字符串,表示操作符。函数根据operator的值来判断要进行加法还是减法,并返回计算结果。
例如,要求输出6-5的值,可以使用以下代码:
val result = calc(6, 5, "-")
println(result) // 输出1
注意,这只是一个简单的示例函数,并不能完全满足所有需求。例如,它并未处理a和b为负数的情况,也没有考虑操作符不是"+"或"-"的情况。如果需要,可以在函数中加入更多的判断条件和代码来实现更复杂的功能。
Kotlin的延迟初始化
Kotlin中有两种延迟初始化的方式。一种 lateinit var ,一种 by lazy
在AS中Tools—》Kotlin—》show Kotlin Bytecode—》Decompile反编译Kotlin字节码得到
可以看到:我们在引用变量的时候会进行判断,如果为空(也就是未初始化),就会抛出异常。
by是属性委托关键字
注释:使用指定的初始化函数。默认返回了SynchronizedLazyImpl对象:
我们反编译Kotlin字节码得到
可以看到,生成了一个getter方法,return一个(String)var1.getValue(),也就是获取str会通过getValue。而SynchronizedLazyImpl实现了Lazy的value方法, 调用getValue方法返回_value, _value默认值是UNINITIALIZED_VALUE,表示为初始化,就会调用传入的initializer进行初始化,并把值赋给 _value,以后每次调用直接返回。
lateinit var和by lazy都可以推迟初始化,lateinit var只是在编译期忽略对属性未初始化进行检查,何时初始化还需开发者自行决定。而by lazy在被第一次调用的时候能自动初始化,做到了真正的延迟初始化的行为。
kotlin继承
类和接口的继承通过 : 来实现
kotlin 的接口可以包含抽象方法,以及方法的实现,接口可以有属性但必须是抽象的,或者提供访问器的实现,当然java 8 中的接口也支持这些特性了。
在kotlin中定义一个虚类,语法与java相似,在虚类中,可以声明类属性,构造函数,可以只定义方法头,也可以定义个包含方法体的完整方法。
子类在实例化的时候,没有实例化父类,那为什么要调用父类的构造函数呢?主要是为了对字段属性进行初始化。
提出类的继承机制的初衷,大体上处于以下两个方面考虑:
关于类型转换,有两条不成文的规则:
在基于面向接口设计原则开发程序时,必定会发生以下两种转换:
在第二步中,将基类强制转换为子类,是正确的——因为基类变量实际上指向的是子类实例对象
在kotlin中提供的强制转换语法是 as , 判断一个类型是 is (代替了java 中的 instanceof)
Kotlin笔记(扩展)
扩展功能
扩展函数中的关键字this对应于接收器对象(在点之前传递的对象)。现在,您可以在 任何MutableList 对象上调用这样的函数:
此函数对任何MutableList 对象都有意义,您还可以在其中加入泛型:
扩展是静态解析的
扩展实际上并不修改它们所扩展的类。通过定义扩展,您不会将新成员插入到类中,而只是使新函数可以使用这种类型的变量的点符号调用。扩展函数是 静态 调度的,被调用的扩展函数是由调用函数的 接收器 类型所对应的 表达式 的决定,而不是由在运行时计算该表达式的结果类型决定。例如:
如果一个类有一个成员函数,并且定义了一个具有相同接收器类型、相同名称并且适用于给定参数的扩展函数,则成员函数的优先级更高。例如:
但是,扩展函数完全可以重载同名但签名不同的成员函数:
可空接收器
请注意,可以使用可为空的接收器类型定义扩展。即使对象变量的值为空,也可以在对象变量上调用这些扩展,并且可以扩展函数内部检查this == null。这样,您可以在不检查null的情况下调用toString(),因为检查发生在扩展函数内部:
扩展属性
Kotlin 支持扩展属性,就像它支持函数一样:
由于扩展实际上并不将成员插入到类中,因此扩展属性没有有效的方法来拥有 支持字段 。这就是 扩展属性不允许使用初始化程序的 原因。它们的行为只能通过显式提供 getter/setter 来定义。
伴随对象的扩展
如果一个类定义了 伴随对象 ,您还可以为伴随对象定义扩展函数和属性。就像 伴随 对象的常规成员一样,它们可以仅使用类名作为限定符来调用:
扩展的范围
在大多数情况下,您在顶层定义扩展,直接在包下:
如果调度接收器和扩展接收器的成员之间发生名称冲突,则扩展接收器优先。要引用调度接收者的成员,您可以使用 限定的this语法 。
注意可见性
kotlin入门(3)-数组
Kotlin入门(1)-环境配置
kotlin入门(2)-基本类型
数组在 Kotlin 中使用 Array 类来表示,它定义了 get 与 set 函数(按照运算符重载约定这会转变为 )以及 size 属性,以及一些其他有用的成员函数。
先来看一下原生数组都有哪些:
其实这些就相当于Java中的 int 等等
先来看一下Java创建数组:
kotlin创建数组:
如果是基本类型的数组可以用文章头的那些类,例如:
一般创建数组,我们直接使用 arrayOf() 就好了
如果不知道自己的写的数据是什么类型,可以在AS中按快捷键Ctrl+Shift+P来查看
创建空数组:
其他创建数组方式:
it 指的是索引值, {} 相当于是一个函数, 可以根据 it 任意设置
方式一
方式二,通过索引
方式三,函数式
kotlin之构造函数(constructor)
个人博客:haichenyi.com。感谢关注
java中的构造函数是与类名相同即可,kotlin里面的构造函数是用constructor关键字表示。
kotlin里面的构造函数分为主构造函数和次构造函数。 主构造函数只能有一个,次构造函数个数不限制,可以有一个或者多个
啥是主构造方法?啥是次构造方法呢?
我们可以看到主构造方法是没有方法体的,那么,我们需要初始化的数据应该放到哪呢?kotlin提供了init方法,给我们初始化数据。
那么,问题来了,次构造方法有方法体,会执行这个init模块吗?
结论: 不管是什么构造方法,先执行init模块逻辑,后执行构造方法的逻辑
简单的说一下继承,this和super两个关键字,跟java差不多;
this是调用自己的,super是调用父类的
类BBB继承类AAA,其中BBB分别有一个参数的构造方法和两个参数的构造方法;一个参数的构造方法用的this关键字调用自己的两个参数的构造;而两个参数的构造方法用的super关键字调用的父类两个参数的构造方法;这里控制台打印的数据:
说到了这个类,讲一下怎么重写属性的set/get方法
这里一个person类,里面有三个属性:name,age,address;在name和age下面分别写了set,get方法,address没写。
重点:
这里,我就只重写了name和age的set,get方法,没有重写address的set,get方法
这里,我再存名字的时候在名字的后面加上了www,在获取的时候又加上了zzz,也就是说,如果你这里name传的是"小王",那么你用get方法取到的name的值应该是"小王wwwzzz"
存age的时候,自己分析一下吧,很简单。
kotlin 函数怎么返回多个值
用Pair或Triple就行了,得到返回结果以后用解构声明把值取出来。
Pair可以装两个值,Triple可以装三个,如果不够,自由嵌套就行了,如果再多,我建议你用list或map。
fun returnPair(): Pair《Int, Pair《Int, String》》 {
return Pair(1,Pair(2,"ss"))
}
fun usePair(){
val (i1,pair) = returnPair()
val (i2, s) = pair
println(i1)
println(i2)
println(s)
}
fun returnTriple(): Triple《Int, String, Pair《Int, String》》 {
return Triple(1,"s",Pair(2,"ss"))
}
fun useTriple(){
val (i1,s1,pair) = returnTriple()
val (i2, s2) = pair
println(i1)
println(i2)
println(s1)
println(s2)
}

更多文章:
androidapp源码免费下载(如何实现APK的反编译得到APK的源码)
2026年9月22日 18:00
service pack 3(操作系统版本升级(SP) Service Pack 3当中的“Service Pack 3”是什么意思)
2026年9月22日 10:20
html代码怎么写大佬教程(html网页的题来个大佬,写代码,题目在图上)
2026年9月22日 10:10
结构体内又一个struct(c++ 在结构体中再嵌入一个结构体如何调用)
2026年9月22日 09:40
cocos creator中文(cocoscreator和cocoscreator3d的区别)
2026年9月22日 02:30






