Kotlin语言基础笔记

Kotlin是一门非常方便的开发语言,它的语法糖有很多,要想要很熟练的掌握kotlin语言,只有不断地使用kotlin写代码,从而达到量到质的一个改变。本文也只是介绍其中的一点内容,内容很松散,有些知识点需要自己动手去写,去实现才能真正体会其中的魅力。

1 高阶函数

1.1 Lambda表达式

分析高阶函数的基础是lambda表达式,先看一下常见的Lambda表达式的使用方式。

Kotlin 复制代码
fun main() {

    // () -> Unit    空参函数  并且 没有返回值  函数名=method01

    // TODO 定义没有问题,调用不行
    /*var method01 : () -> Unit
    method01() // 不能调用  没有具体的实现

    var method02 : (Int, Int) -> Int
    method02(9, 9)

    var method03: (String, Double) -> Any?
    method03("Derry", 543354.4)

    var method04 : (Int, Double, Long, String ? ) -> Boolean
    method04(1, 545, 3543, null)

    var method05 : (Int, Int) -> Int
    method05(9, 9)*/

    // : (形参类型)
    // = {具体详情}

    // TODO 定义没有问题,调用OK ,因为有实现了
    var m06 : (Int, Int) -> Int = {number1, number2 -> number1 + number2}
    println("m06:${m06(9, 9)}")

    var m07 = { number1: Int , number2: Int -> number1.toDouble() + number2.toDouble()}
    println("m07:${m07(100, 100)}")

    var m08 : (String, String) -> Unit = {aString, bString -> println("a:$aString,  b:$bString")}
    m08("李元霸", "王五")

    var m09 : (String) -> String = {str -> str}
    println("m09:${m09("降龙十八掌")}")

    var m10 : (Int) -> Unit = {
        when(it) {
            1 -> println("你是一")
            in 20..30 -> println("你是 二十 到 三十")
            else -> println("其他的数字")
        }
    }
    m10(29)

    var m11 : (Int, Int, Int) -> Unit = { n1, n2, n3 ->
        println("n1:$n1, n2:$n2, n3:$n3")
    }
    m11(29,22,33)

    var m12 = { println("我就是m12函数,我就是我") }
    m12()

    val m13 = {sex: Char -> if (sex == 'M') "代表是男的" else "代表是女的"}
    println("m13:${m13('M')}")

    // 覆盖操作
    var m14 = {number: Int -> println("我就是m14  我的值: $number")}
    m14 = {println("覆盖  我的值: $it")}
    m14(99)

    // 需求:我想打印, 并且,我还想返回值,就是 我什么都想要
    var m15 = { number: Int -> println("我想打印: $number")
        number + 1000000
    }
    println("m15:${m15(88)}")
}

代码中的注释有对应的解释,此处我们不做过多的赘述,上面一共展示了15中Lambda表达式的使用方式,其实总结下来就2种形式:

Kotlin 复制代码
// : (形参类型)
// = {具体详情}

对于Lambda表达式,至于说到底什么是Lambda表达式,其实我理解他就是一种规则,允许在编程过程中使用的一种规则。说穿了没有什么高深的东西,就是多多练习使用后熟能生巧的一个过程,这里只介绍这种语法糖即可。

1.2 扩展函数

java 复制代码
fun main() {
    val stu = Student()
    stu.add(100, 200)

    // KT本来就有
    val file = File("///")
    file.readText()
    file.show()
}

// 扩展 函数
fun Student.add(n1: Int, n2: Int) {
    println("结果:${n1 + n2}")
}

fun Student.show() {
    println("Student show")
}

// 给 java File 增加 扩展函数
fun File.show() {
    println("给 java File 增加 扩展函数")
}

扩展函数可以理解为在外部对已有的类添加函数,什么意思呢,说穿了就是不想改动原来的类,但是呢又想对类的功能进行扩展,保持了原有的实现,然后又扩展了一项功能,使得其他的该类的变量都能够进行使用,这就是扩展函数的核心。

1.3 高阶函数

高阶函数的理解:如果在函数上用到了Lambda表达式,那该函数就属于高阶函数。

Kotlin 复制代码
fun main() {
    show(true) {
        // println(it)
        'M'
    }
}

// TODO  loginMethod:(Boolean)->Unit

fun loginMethod(b: Boolean) : Unit {

}

// loginMethod 方法名
// (Boolean)方法的那个括号
// -> 方法体 干活
// Unit == void

fun show(isLogin: Boolean, loginMethod:(Boolean)->Char) {
    if (isLogin) {
        println("登录成功")
        val r = loginMethod(true)
        println(r)
    } else {
        println("登录失败")
        loginMethod(false)
    }
}

上面简单的举了一个扩展函数的例子,具体的解释代码中已经注释了,其实高阶函数,就是在参数中定义了一个Lambda表达式。

其实我们平时使用的let、run、with、apply、also都是一些高阶的扩展函数,我们来分析一下具体的实现,感受一下高阶函数的魅力:

Kotlin 复制代码
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}

@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, Invoc ationKind.EXACTLY_ONCE)
    }
    return block(this)
}

@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}

@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

总结:

also let :

使用的参数传递调用者对象的方式,也就是将调用者的对象以参数的形式传入到高阶函数中,然后通过"调用者对象参数.方法"的方式调用调用者对象中的方法。

返回值不一样,also的返回值是调用者对象本身,let的返回值是高阶函数实现体的最后一行代码的返回值类型。

apply、with、run:

都是通过对调用者对象增加匿名函数的方式实现,这样做的好处是在高阶函数的具体实现中全局的增加了一个this对象,随时都可以直接调用调用者对象中的其他方法,不需要使用"this.方法"的方式。

返回值不一样,apply返回的是调用者本身,with run返回的是高阶函数的最后一行代码的返回类型。

1.4 Kt关键字in out

此处多提一下,kotlin中有2个关键字:in和out,其实这2个关键字比较好理解,只要你理解了之前分析的泛型中的extend和super关键词,那么我们肯定就能理解,来看一下Java中泛型的读取模式:

java 复制代码
    // 泛型读取模式
    void test01() {

        // ? extends FuClass  == 只能获取,不能修改
        List<? extends FuClass> list = new ArrayList<ZiClass>();

        // 不能修改
        /*list.add(fuClass);
        list.add(ziClass);*/

        // 能获取
        FuClass fuClass = list.get(0);

        // TODO  =============================================


        // ? super ZiClass == 只能修改,不能获取
        List<? super ZiClass> list2 = new ArrayList<FuClass>();

        // 能添加
        list2.add(ziClass);

        // 不能获取
        // ZiClass ziClass = list2.get(0);
    }

extend是只能获取不能修改,super是只能修改不能获取。那么kotlin中extend对应的out,super对应的in。

Kotlin 复制代码
fun test01() {
    // out 只能取,不能修改   == ? extends FuClass
    val list: MutableList<out FuClass> = ArrayList<ZiClass>()

    // in 只能修改(存), 不能获取   === ? super ZiClass
    val list2: MutableList<in ZiClass> = ArrayList<FuClass>()
}
Kotlin 复制代码
// 这个类,就是只能获取,不能修改了
// 声明的时候加入  一劳永逸了<in T>
class Worker <out T> {

    // 能获取
    fun getData() : T? = null

    // 不能修改
    /*fun setData(data: T) {

    }

    fun addData(data: T) {

    }*/
}
Kotlin 复制代码
// 这个类,就是只能修改, 不能获取
// 声明的时候加入  一劳永逸了<in T>
class Student<in T> {

   /*fun a(list: MutableList<in T>) {

    }

    fun a2(list: MutableList<in T>) {

    }

    fun a3(list: MutableList<in T>) {

    }

    fun a4(list: MutableList<in T>) {

    }

    fun a5(list: MutableList<in T>) {

    }*/

    fun setData(data: T) {}

    fun addData(data: T) {}

    // 不能获取
    // fun getData() : T
}

2 协程

2.1 协程的使用

协程的使用主要是2个方式runBlocking和GlobalScope.launch的方式,具体看一下实现

Kotlin 复制代码
fun click3(view: View) = runBlocking {
	// TODO 完成这种  异步线程  和  主线程  的切换,  这个需求:之前我们用RxJava实现过了哦
	// 1.注册耗时操作
	// 2.注册耗时操作完成后,更新注册UI
	// 3.登录耗时操作
	// 4.登录耗时操作完成后,更新登录UI

	// main
	launch {

		val pro = ProgressDialog(this@MainActivity)
		pro.setMessage("正在执行中...")
		pro.show()

		withContext(Dispatchers.IO) {
			// 1.注册耗时操作  异步
			Log.d("click3", "1.注册耗时操作: ${Thread.currentThread().name}")
			Thread.sleep(2000)
		}

		// 2.注册耗时操作完成后,更新注册UI  main
		Log.d("click3", "2.注册耗时操作完成后,更新注册UI: ${Thread.currentThread().name}")

		withContext(Dispatchers.IO) {
			// 3.登录耗时操作  异步
			Log.d("click3", "3.登录耗时操作: ${Thread.currentThread().name}")
			Thread.sleep(3000)
		}

		// 4.登录耗时操作完成后,更新登录UI
		Log.d("click3", "4.登录耗时操作完成后,更新登录UI: ${Thread.currentThread().name}")

		// pro.dismiss()
	}

}

runBlocking平时的开发中一般是不用的,一般是在测试过程中使用,因为runBlocking是阻塞式的。

Kotlin 复制代码
// 非阻塞
fun click4(view: View)  {
	// TODO 完成这种  异步线程  和  主线程  的切换,  这个需求:之前我们用RxJava实现过了哦
	// 1.注册耗时操作
	// 2.注册耗时操作完成后,更新注册UI
	// 3.登录耗时操作
	// 4.登录耗时操作完成后,更新登录UI

	// main
	GlobalScope.launch (Dispatchers.Main) {

		val pro = ProgressDialog(this@MainActivity)
		pro.setMessage("正在执行中...")
		pro.show()

		withContext(Dispatchers.IO) {
			// 1.注册耗时操作  异步
			Log.d("click3", "1.注册耗时操作: ${Thread.currentThread().name}")
			Thread.sleep(2000)
		}

		// 2.注册耗时操作完成后,更新注册UI  main
		Log.d("click3", "2.注册耗时操作完成后,更新注册UI: ${Thread.currentThread().name}")
		textView.text = "注册成功,你可以去登录了"
		pro.setMessage(textView.text.toString())

		withContext(Dispatchers.IO) {
			// 3.登录耗时操作  异步
			Log.d("click3", "3.登录耗时操作: ${Thread.currentThread().name}")
			Thread.sleep(3000)
		}

		// 4.登录耗时操作完成后,更新登录UI
		Log.d("click3", "4.登录耗时操作完成后,更新登录UI: ${Thread.currentThread().name}")
		textView.text = "登录成功,欢迎回来"
		pro.setMessage(textView.text.toString())

		pro.dismiss()
	}

}

2.2 协程的原理

至于原理,有一篇博客讲解的很好,大家可以参考:https://www.jianshu.com/u/a324daa6fa19

相关推荐
前行的小黑炭10 小时前
Android :如何提升代码的扩展性,方便复制到其他项目不会粘合太多逻辑,增强你的实战经验。
android·java·kotlin
珠峰下的沙砾12 小时前
在kotlin中如何使用像java中的static
kotlin
用户091 天前
Android View 事件分发机制详解及应用
android·kotlin
ForteScarlet1 天前
Kotlin 2.2.20 现已发布!下个版本的特性抢先看!
android·开发语言·kotlin·jetbrains
珠峰下的沙砾1 天前
Kotlin中抽象类和开放类
kotlin
Kapaseker1 天前
如果你的 View 不支持 Compose 怎么办
android·kotlin
前行的小黑炭1 天前
Android:在项目当中可能会遇到的ANR,应该如何解决?
android·java·kotlin
FunnySaltyFish2 天前
Kotlin 2.2.20 上新:新contract、跨平台编译稳定、默认Swift导出……
kotlin
alexhilton2 天前
runBlocking实践:哪里该使用,哪里不该用
android·kotlin·android jetpack
萧雾宇2 天前
Android Compose打造仿现实逼真的烟花特效
android·flutter·kotlin