fun pay(block: Runnable) {
println(“before block”)
block.run()
println(“end block”)
}
fun pay(block: () -> Unit) {
println(“before block”)
block()
println(“end block”)
}
输出的结果:
before block
回调函数
end block
before block
高阶函数
end block
这看不出啥区别,当需求发生变化,我想在回调方法中加个String
类型的参数,该如何实现呢?
1.2 带参示例
// 定义接口
interface Consumer {
fun accept(way: String)
}
fun main() {
pay(Consumer {
println(“回调函数…it=$it”)
})
pay{
println(“高阶函数…it=$it”)
}
}
fun pay(block: Consumer) {
println(“before block”)
block.accept(“支付宝”)
println(“end block”)
}
// String 指的是方法参数
fun pay(block: (String) -> Unit) {
println(“before block”)
block(“支付宝”)
println(“end block”)
}
// Int 指的是block函数的返回值
fun pay2(block: (String) -> Int) {
println(“before block”)
block(“支付宝”)
println(“end block”)
}
-
如果是以回调的形式,得先创建一个接口,定义参数,如果后面参数变成2个,又得新建1个接口。
-
而
kt的高阶函数
用起来更加灵活。
二 🌵内联函数
========
2.1 介绍
-
定义:方法名前面 加个
inline
就是内联函数 -
作用:减少函数的调用来优化性能
-
使用场景:并不是每个函数前加一个 inline 就可以优化性能,如果某个方法的参数包含
高阶函数
,那建议加上inline。典型的一个应用场景就是Kotlin的集合类。
filter
和 map
方法里的参数都是高阶函数,所以这2个方法加上 inline
关键字后,调用这2个方法时,会减少嵌套, 优化性能,见下面示例。
2.2 非内联函数
fun main() {
pay(Runnable {
println(“回调函数…”)
})
payNoInline{
println(“高阶函数…”)
}
}
fun pay(block: Runnable) {
println(“before block”)
block.run()
println(“end block”)
}
fun payNoInline(block: () -> Unit) {
println(“before block”)
block()
println(“end block”)
}
通过字节码反编译的相关Java代码如下:
-
发现高阶函数作为参数时和方法回调没什么区别,
-
并且方法参数中还新增加了额外的类
Function0
和block.invoke()
函数调用开销。
2.3 🔥内联函数
fun main() {
pay(Runnable {
println(“回调函数…”)
})
payInline{
println(“高阶函数…”)
}
}
…
fun payInline(block: () -> Unit) {
println(“before block”)
block()
println(“end block”)
}
通过字节码反编译的相关Java代码如下:
-
当调用 payInline( 高阶函数) 时,会把 payInline()里面的方法体取过来并和当前高阶函数合成一个整体执行。
-
不会调用 payInline()方法,不会调用block.invoke(),执行效率提高了许多。
-
当函数里的某个参数为高阶函数时,建议您使用
inline
修饰该函数。
三 🌷泛型
======
3.1 🔥reified 强烈推荐
- reified 是kt语言在泛型中独有的关键字,作用是把抽象的东西更加具体或真实,让泛型用起来更简单安全。
inline fun Activity.openAct() {
startActivity(Intent(this, T::class.java))
}
fun Activity.openAct(clazz: Class) {
startActivity(Intent(this, clazz))
}
fun main(){
// 启动Activity的方式1
openAct(MyAct::class.java)
// 启动Activity的方式2
openAct()
}
使用 reified
时,必须和inline
一起。再见 .class.java
,你好 reified
3.2 上界约束(out or extend)
-
java:
T extends Object
-
kotlin:
T : Object
和out : Object
指的是其类型必须是它的子类型或者它自己。out
一般将泛型作为某个对象返回, 详情见下面 out
协变讲解。
类的关系图如下:
open class People
open class Man : People()
class Man1 : Man()
class Man2 : Man()
class User
fun createUser(user4: User4){}
fun main()
var u = User() // 泛型可以是自己
var u1 = User() // 泛型可以是子类
// var u2 = User() // 编译错误
val c1 = createUser(User4(Man1()))
// val c2 = createUser(User4(People())) // 编译错误
}
3.3 下界约束(in or super)
-
java中是
? super Object
-
kotlin中是
in Object
open class People
open class Man : People()
class Man1 : Man()
class Man2 : Man()
class User
fun main() {
var list: ArrayList?= ArrayList()
list.add(Man())
// 为什么可以添加进去呢?因为编译器会这么去存list.add((Man)Man1)
// 小转大是隐性的,大转小强转才需要手动加类型。
list.add(Man1())
// 那这里为什么又不能存 Man 的父类呢?
// 因为手动add()进去的数据都必须是绝对安全的(最低级父类:本身)才能通过。所以直接add父类也是不行的。
最后
有任何问题,欢迎广大网友一起来交流,分享高阶Android学习视频资料和面试资料包~
偷偷说一句:群里高手如云,欢迎大家加群和大佬们一起交流讨论啊!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
an>?= ArrayList()
list.add(Man())
// 为什么可以添加进去呢?因为编译器会这么去存list.add((Man)Man1)
// 小转大是隐性的,大转小强转才需要手动加类型。
list.add(Man1())
// 那这里为什么又不能存 Man 的父类呢?
// 因为手动add()进去的数据都必须是绝对安全的(最低级父类:本身)才能通过。所以直接add父类也是不行的。
最后
有任何问题,欢迎广大网友一起来交流,分享高阶Android学习视频资料和面试资料包~
偷偷说一句:群里高手如云,欢迎大家加群和大佬们一起交流讨论啊!
[外链图片转存中…(img-Q31VDo5k-1715669071077)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!