Kotlin知识点/面试点2

2020-12-25 10:03:29 浏览数 (1)

前言

今天继续kotlin相关的知识点和常考考点,通过这些问答相信你也能更一步了解Kotlin

可以定义同名的扩展方法吗

在同一个包名下,是不可以定义相同类相同方法名的扩展方法的。但是,在不同包名下,是可以定义的。

比如我在不同的包名下定义了相同的扩展方法:

代码语言:javascript复制
//Utils2.kt
package com.example.studynote.kotlin

fun Activity.showToast(msg:String){
    Toast.makeText(this,msg,Toast.LENGTH_LONG).show()
}



//Utils.kt
package com.example.studynote

fun Activity.showToast(msg:String){
    Toast.makeText(this,msg,Toast.LENGTH_SHORT).show()
}

具体会用哪个呢?就要看你导入的包是哪个了~

扩展方法可以覆盖掉某个类的已有方法吗

肯定是不能的,如果一个类的扩展方法和它已有方法同名,是可以编译过的。

但是调用的时候会优先调用类中本来就有的方法,而不是扩展方法。

kotlin中有没有用到;的时候

kotlin中一般会把省略,但是有两种情况还是会用到:

  • 枚举中,如果有方法的情况,必须用来分割枚举常量列表和方法
代码语言:javascript复制
enum class Color {
    RED,
    BLACK,
    BLUE,
    GREEN,
    WHITE;

    fun getTopColor():Color {
        return BLACK
    }
}
  • 两个表达式在一行的时候,当然这种有点累赘,为啥要写成一行呢是吧:
代码语言:javascript复制
var test="nihao" ; var test2="heihei"

let、apply、with、run

  • let 默认当前这个对象作为闭包的it参数,返回值为函数最后一行,或者return
代码语言:javascript复制
    fun getInt():Int{
        "jimu".let {
            println(it.length)
            return 0
        }
    }
  • apply 在apply函数范围内,可以任意调用该对象的任意方法,并返回该对象
代码语言:javascript复制
    fun getInt(): Int {
        return ArrayList<String>().apply {
            add("jimu")
        }.size
    }
  • with 返回值是最后一行,这点类似let。可以直接调用对象的方法,这点类似apply。
代码语言:javascript复制
    fun getInt(): Int {
        return with(ArrayList<String>()){
            add("jimu")
            size
        }
    }
  • run run和with很像,可以调用对象的任意函数,返回值是最后一行
代码语言:javascript复制
    fun getInt(): Int {
        return ArrayList<String>().run{
            add("jimu")
            size
        }
    }

lateinit和by lazy

上篇说过,Kotlin有空限制,所以有些变量如果不想设置为空的时候初始化该怎么做呢?这就用到延迟初始化了,lateinit和by lazy都能实现。

  • lateinit

lateinit用于修饰var变量,它会让编译器暂时忽略初始化这个事情,到后面用的时候我们在进行初始化,但是不能用到基本数据类型,比如int,double这种。

代码语言:javascript复制
lateinit var test: String
  • by lazy

by lazy用于val类型的变量,它会暂时不进行初始化,并且在第一次使用的时候自动调用我们设置好的表达式进行初始化。

代码语言:javascript复制
val str by lazy {
        println("Init lazy")
        "Hello World"
    }

构造函数

kotlin中构造函数分为主构造函数和次构造函数。

  • 主构造函数

主构造函数没有函数体,直接定义在类名后。每个类都会默认带一个不带参数的构造函数,也可以直接定义参数,如果需要在构造函数中进行初始化工作,可以用init关键字:

代码语言:javascript复制
class Student {
}

class Student(var name: String) {
    init {
        Log.e(TAG,"name=$name")
    }
}

class Student constructor(var name: String) {
    init {
        Log.e(TAG,"name=$name")
    }
}
  • 次构造函数

除了类名后这种主构造函数,其他的构造函数方法就是通过constructor关键字来定义次构造函数,一个类可以定义多个次构造函数。如果主构造函数和次构造函数同时存在的时候,次构造函数必须调用主构造函数。

代码语言:javascript复制
class Student{
    private val username: String
    constructor(username: String){
        this.username = username
    }
}


class Student(username: String) {
    private var username: String
    private var age: Int

    init {
        this.username = username
        this.age = 10
    }

    constructor(username: String, age: Int) : this(username) {
        this.age = age
    }
}


协程

Kotlin协程是对线程的一种封装,同样是用来解决并发任务(异步任务)的方案,可以理解为一种线程框架,特点是挂起时不需要阻塞线程,更好的解决了线程切换,魔鬼调用的问题。

简单举个例子,具体的说明大家可以翻翻以前的文章——协程三问。

代码语言:javascript复制

GlobalScope.launch(Dispatchers.Main) {
    var name = ioTask()
    updateUI(name)
    var name1 = ioTask()
    updateUI(name1)
    var name2 = ioTask()
    updateUI(name2)
}

private suspend fun ioTask(): String {
    var name = ""
    withContext(Dispatchers.IO) {
     //耗时操作,比如网络接口访问
        name = "jimu"
    }
    return name
}
  • GlobalScope.launch去开启一个协程
  • Dispatchers.Main表示运行在主线程
  • suspend关键字用于标记挂起函数的关键字
  • withContext函数用来构建一个协程作用域,可以标明作用线程,比如这里的Dispatchers.IO。这个函数必须在挂起函数或者协程中执行

感谢大家的阅读,有一起学习的小伙伴可以关注下公众号—码上积木❤️❤️ 每日三问知识点/面试题,积少成多。

0 人点赞