问: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)