Android面试Kotlin基础篇(六)

问:Kotlin的两种延迟初始化,他们的区别是什么?

答:一种是lateinit var,一种是by lazy
lateinit var: 它只能用来修饰类属性,不能用来修饰局部变量,并且只能用来修饰对象,不能用来修饰基础数据类型(基础数据类型在类加载后的准备阶段会自动给一个初始值)。作用于编译器时,不去检查有没有初始化对象,但是可能在运行时报错,最好使用isInitialized来判断是否已经初始化。
by lazy: 它其实是一种代理对象,在使用时才初始化,by lazy可以使用于类属性或者局部变量,且只能修饰val不可变对象,类似于Java中的final对象。

虽然两者都可以推迟属性初始化的时间,但是lateinit var只是让编译期忽略对属性未初始化的检查,后续在哪里以及何时初始化还需要开发者自己决定。
而by lazy真正做到了声明的同时也指定了延迟初始化时的行为,在属性被第一次被使用的时候能自动初始化。

问:let,apply,run,with,aslo,等函数的区别(https://blog.csdn.net/u013064109/article/details/78786646)

答:with 它是将某对象作为函数的参数,在函数块内中使用this代表对象,this可以省略。返回值为函数块的最后一行或指定return表达式。适用于调用同一个类的多个方法时,可以省去类名重复,直接调用类的方法即可。如:

  fun testWith() {
    // fun  with(receiver: T, f: T.() -> R): R = receiver.f()
    with(ArrayList()) {
        add("testWith")
        add("testWith")
        add("testWith")
        println("添加结果"+this.toString())    //打印结果:添加结果[testWith, testWith, testWith]
        "返回结果"+this.toString()    //作为with函数的返回结果
    }.let { println(it) }    //打印结果:返回结果[testWith, testWith, testWith]
}

let 默认当前这个对象作为闭包的it参数,返回值是函数里面最后一行,或者指定return。最常用的场景就是使用let函数处理需要针对一个可null的对象统一做判空处理

fun testLet(): Int {
    // fun  T.let(f: (T) -> R): R { f(this)}
    "testLet".let {
        println(it)    //打印结果:testLet
        return 1    //作为结果
    }
}

apply 调用某对象的apply函数,在函数范围内,可以任意调用该对象的任意方法,并返回该对象。apply一般用于一个对象实例初始化的时候,需要对对象中的属性进行赋值

fun testApply() {
    // fun  T.apply(f: T.() -> Unit): T { f(); return this }
    ArrayList().apply {
        add("testApply")
        println("this = " + this)    //打印结果:this=[testApply]
    }.let { println(it) }  //打印结果 [testApply]
}

run run函数和apply函数很像,只不过run函数是使用最后一行的返回,apply返回当前自己的对象。with和let的结合体,弥补了let中必须使用it来代表对象的问题,也可以做判空处理

fun testRun() {
    // fun  T.run(f: T.() -> R): R = f()
    "testRun".run {
        println("this = " + this)    // this = testRun
    }.let { println(it) }      // kotlin.Unit
}

aslo 与let类似,执行代码块,但返回this自身,

fun testAslo(){
  //fun  T.also(block: (T) -> Unit): T {}
  var aslo = "testAslo".aslo{
    println(it)    //打印:testAslo
  }
  println(aslo)     //打印:testAslo
}
问:Kotlin中如何实现静态方法

答:单例类、companion object、顶层方法等可以实现静态方法效果,但是Java中要调用Kotlin中的静态方法需要在companion object中的方法之上加上@JvmStatic 注解,使得方法变成真正的静态方法。

//1、单例类
object Utils{
  //使用Utils.doAction
  fun doAction(){
  }
}

//companion object
class Utils{
  //使用时  Utils.doAction()
  companion object{
    fun doAction(){
    }
  }
}

//顶层方法---在任意一个kt文件中写一个方法即为顶层方法,在程序的任意一个地方直接使用
//新建Utils.kt文件
fun doAction(){
  //在任意地方都可以直接调用doAction() 
}

//真正的静态方法:
class Utils{
  //使用时  Utils.doAction()
  companion object{
    @JvmStatic    //增加方法注解,在编译时会编译成静态方法
    fun doAction(){
    }
  }
}
问:Kotlin中密封类的作用

答:密封类:sealed class 密封类是一个可以继承的类。密封类变量作为参数、条件时,Kotlin编译器会自动检查该类有哪些子类。密封类及其所有子类只能定义在同一个文件的顶层位置,不能嵌套在其他类中。例如:

//新建一个Result.kt文件 
interface Result
class Success(val msg:String):Result
class Failure(val error:Exception):Result
//使用时,如果新增一种未知状态继承如:class Unknown(val error:Exception):Result
fun getResult(result:Result) = when(result){
  is Success ->{result.msg}
  is Failure ->{result.error.message}
  //此处如果不加is Unknow,不会提示报错,但是运行时有可能执行else抛出异常了
  else ->{throw IllegalArgumentException}  //如果非密封类,必需编写这个无用的分支
}

//------修改为密封类
sealed class Result      //接口修改密封类 sealed class 
class Success(val msg:String):Result()    //Result是一个普通的可继承类,最后需要()
class Failure(val error:Exception):Result()
//使用时--如果增加一个子类,则在使用的地方会显示提醒异常
fun getResult(result:Result) = when(result){
  is Success ->{result.msg}
  is Failure ->{result.error.message}
}
问:Kotlin中的扩展函数

答:扩展函数表示即使在不修改某个类的源代码的情况下,仍然可以打开这个类,向该类添加新的函数。最好定义为顶层方法,使其作用于全局。

//扩展函数的定义
fun 类名.方法名(参数1:类型,参数2:类型):返回类型{
  
}
//例如:
//定义吐司方法
fun String.showToast(context:Context){
  Toast.makeText(context, this,Toast.LENGTH_LONG)
}

//使用
"测试Toast".showToast(this)

你可能感兴趣的:(Android面试Kotlin基础篇(六))