笔记来自学习即刻时间 – 快速上手Kotlin开发,扔物线 – 码上开学,等等…
内联函数
-
一般在比较小的方法上,以及频繁使用的方法上使用,而不会随意使用。
-
内联函数可以中断外部调用的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
fun test() { inlineTest { println("hello1") return println("hello2") } println("hello3") } private inline fun inlineTest(l: () -> Unit) { l.invoke() return } // 输出: // hello1
-
使用
crossinline
不允许 inline 的 Lambda 中断外部函数的执行。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
fun test() { inlineTest { println("hello1") return@inlineTest println("hello2") } println("hello3") } private inline fun inlineTest(crossinline l: () -> Unit) { l.invoke() return } //输出: //hello1 //hello3
-
使用
noinline
拒绝内联。
扩展函数
扩展函数会被当作静态函数对待,所以不存在被子类重写这种操作。
访问修饰符
- internal : 模块内可访问修饰符,但在 java 中,会被直接当作 public 使用的。
黑科技(使用 Kotlin 的特性,不让 Java 调用)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 在kotlin中是合法的
fun `1234`(){//是无法兼容 Java 的
println("function 1234")
}
//在 kotlin 中可以调用
fun main(args: Array<String>) {
`1234`()
}
// 在Java中不能调用
public void test() {
1234();//ERROR: 不合法调用
`1234`();//ERROR: 不合法调用
}
单例
除了 object 来声明单例外,还可以使用伴生对象来实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Single private constructor() {
companion object {
fun get(): Single {
return Holder.instance
}
}
private object Holder {
val instance = Single()
}
}
fun main(args: Array<String>) {
val single = Single.get()
}
伴生对象
- 可以理解为 匿名内部单例。
动态代理
-
使用 by 关键字就可以实现,参考:极客时间 – Kotlin。 Kotlin的动态代理会在编译以后转换成静态代理去调用,所以比Java通过反射的方式效率要高。
-
❓究竟何为动态代理,如何使用Kotlin动态代理实现 Retrofit❓
密闭类
完全可以代替枚举类,并且实现更多的扩展,比如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
sealed class SuperCommand {
object UP : SuperCommand()
object LEFT : SuperCommand()
object RIGHT : SuperCommand()
object DOWN : SuperCommand()
class SPEED(var speed: Int) : SuperCommand()
}
fun exec(tank: Tank, superCommand: SuperCommand) {
return when (superCommand) {
SuperCommand.UP -> tank.turnUp()
SuperCommand.LEFT -> tank.turnLeft()
SuperCommand.RIGHT -> tank.turnRight()
SuperCommand.DOWN -> tank.turnDown()
is SuperCommand.SPEED -> tank.speed(superCommand.speed)
}
}
嵌套类
- 在 Java 中,类的内部声明的类为内部类,内部类默认持有外部类的引用,并且不能脱离外部类使用。
- 而在 Kotlin 中,默认是嵌套类,类似于 Java 中的静态内部类,静态内部类和外部类没有关系。
- 在 kotlin 中实现内部类的话,使用inner关键字。
解构
自动将一个对象拆解成若干个变量分别赋值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class User(private val name: String, private val age: Int) {
operator fun component1() = age
operator fun component2() = name
}
fun main(args: Array<String>) {
val user = User("Hurshi", 18)
val (name, age) = user
println("name = $name")
println("age = $age")
}
//常用场景:
fun main(args: Array<String>) {
val map = mapOf<String,String>("name" to "Hurshi","age" to "18")
for((key,value) in map){
println("key = $key ,value = $value")
}
}
循环
1
2
3
4
5
6
7
8
9
10
11
for(i in 1..10) { println(i) }
for(i in 1 until 10) { println(i) }
for(i in 10 downTo 1) { println(i) }
for(i in 1..10 step 2) { println(i) }
repeat(10) { println(it) }
//循环 list with index
list.forEachIndexed { index, value -> println("[$index,$value]") }
for ((index, value) in list.withIndex()) {
println("[$index,$value]")
}
作用域函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
val letResult: String = user.let { it.name }
val runResult: String = user.run { this.name }
val alsoResult: User = user.also { it.name }
val applyResult: User = user.apply { this.name }
user.takeIf { it.name.isNotEmpty() }?.also { println(it.name) }
with(user){
this.name = "haha"
this.age = 18
this.phone = 111111
}
// with 可以替换为:
// user.let {
// it.name = "haha"
// it.age = 18
// it.phone = 111111
// }
中缀表达式(扩展函数)
使用 infix
来扩展函数,比如自定义一个 vs 的中缀表达式:
1
2
3
4
5
6
7
infix fun Int.vs(num:Int):Int{
return if(this<num)-1 else if(this>num) 1 else 0
}
fun main(args: Array<String>) {
println(100 vs 90)
}
反编译
javap [option] *.class
命令,反编译一个 class 文件,比如:
1
javap -c main.class
val 变量并不是常量
1
2
3
4
5
6
7
8
9
10
11
12
class Person(val birthYear: Int) {
var currentYear = 2019
val age: Int
get() = currentYear - birthYear
}
fun main(args: Array<String>) {
val person = Person(1990)
println(person.age)
person.currentYear = 2020
println(person.age)
}
如何真正的声明一个常量?
1
const val a = 0 //const 变量的值必须在编译期间确定下来
空安全
- 局部变量可以通过上下文推断,来避免多次判空。
泛型
-
可以指定多个约束条件,比如
1 2
//要求 T 同时实现了 Callback 和 Runnable 接口 class Test<T> where T : Callback, T : Runnable {}
-
真泛型:
1 2
// java 的 fromJson: public <T> T fromJson(String json, Class<T> classOfT) throw Json...Exception{}
1 2 3 4
// Kotlin 的 fromJson: inline fun <reified T> Gson.fromJson(json: String): T { return fromJson(json, T::class.java) }
-
out / in
:相当于 java 中的<? extends Class>
/<? super Class>
,理解为:- out:只读不可写。
- in:只写不可读。
-
类型擦除/类型安全 ???
-
补充知识:在 Java 中,使用
? extends
定义的比如List<? extends ClassA> list
是不能被修改的,理解为只读。而? super
则是只能写入而不能读。
协程
- 挂起函数 suspend :非阻塞式的挂起。相当于到新线程去执行任务了。
runBlocking {}
是 阻塞的withContext {}
可以切到指定线程去执行代码,结束后再切回来- Channel:用于2个协程之间的通信。一般可以使用 produce 来使用。
BIO NIO
- Blocking IO / Non-blocking IO
- Kotlin 在对’流’操作有语法糖 – use, 使用者不用写那么多的 try catch,而且不用管 流的close。
- 对象缓存池:DefaultPool,缓存对象。
KTX 扩展库
- https://developer.android.com/kotlin/ktx
- 对 LinearLayout 遍历子 View:
linearlayout.foreach { }
- 判断字符串是否只包含数字:
"12343.22333.223".isDigistsOnly()
修改 Kotlin 类名
@file:JvmName("name")
:指定类名。@file:JvmMultifileClass
:当类名冲突的时候,会合并为一个 class。