本文介绍: 另外再多说一句,密封类及其所有子类只能定义在同一个文件的顶层位置,不能嵌套在其他类中,这是被密封底层实现机制限制的。关键字,它可以告诉Kotlin编译器,我会在晚些时候对这个变量进行初始化,这样就不用在一开始的时候将它赋值为。关键字也不是没有任何风险的,如果我们student变量还没初始化调用,那么程序还是会崩溃的,并且会抛出。到目前为止,代码都是没有问题的,但比较让人讨厌的是,接下来我们不得不再编写一个。另外,由于密封类是一个可继承的类,因此在继承它的时候需要在后面加上一对括号

变量延迟初始化

延迟初始化使用的是lateinit关键字,它可以告诉Kotlin编译器,我会在晚些时候对这个变量进行初始化,这样就不用在一开始的时候将它赋值为null了。示例如下

class MainActivity : AppCompatActivity() {

    private lateinit var student: Student


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        student = Student("01", 1)
        student.doHomework()
    }


}

我们使用lateinit关键字对Student对象进行延迟初始化时,我们就不需要像之前章节提到过的一样,再对student进行判空处理,直接可以调用doHomework方法

当然,当我们使用lateinit关键字也不是没有任何风险的,如果我们在student变量还没初始化调用,那么程序还是会崩溃的,并且会抛出UninitializedPropertyAccessException异常

所以,当你对一个全局变量使用了lateinit关键字时,请一定要确保它在被任何地方调用之前已经完成了初始化工作,否则Kotlin将无法保证程序安全性

另外,我们还可以通过代码判断一个全局变量是否已经完成了初始化,这样在某些时候能够有效地避免重复对某一个变量进行初始化操作示例代码如下

class MainActivity : AppCompatActivity() {

    private lateinit var student: Student


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        if (!::student.isInitialized){
            student = Student("01", 1)
        }
        student.doHomework()
    }


}

具体语法就是这样,

::student.isInitialized

用于判断adapter变量是否已经初始化。虽然语法看上去有点奇怪,但这是固定写法然后我们再对结果进行取反,如果还没有初始化,那么就立即对adapter变量进行初始化,否则什么都不用做。

使用密封优化代码

首先来了解一下密封类具体的作用,这里我们来看一个简单例子新建一个Kotlin文件文件名就叫Result.kt好了,然后在这个文件编写如下代码:

interface Result
class Success(val msg: String) : Result
class Failure(val error: String) : Result

这里定义了一个Result接口用于表示某个操作执行结果接口中不用编写任何内容然后定义两个类去实现Result接口:一个Success用于表示成功时的结果,一个Failure用于表示失败时的结果,这样就把准备工作做好了。

然后定义一个getMsg()方法,代码如下所示

fun getMsg(result: Result) = when (result) {
    is Success -> result.msg
    is Failure -> result.error
    else -> throw Exception()
}

getMsg()方法接收一个Result参数。我们通过when语句来判断:如果Result属于Success,那么就返回成功的消息;如果Result属于Failure,那么就返回错误信息。到目前为止,代码都是没有问题的,但比较让人讨厌的是,接下来我们不得不再编写一个else条件,否则Kotlin编译器会认为这里缺少条件分支,代码将无法编译通过。但实际上Result执行结果只可能是Success或者Failure,这个else条件是永远走不到的,所以我们在这里直接抛出了一个异常,只是为了满足Kotlin编译器语法检查而已。

另外,编写else条件还有一个潜在的风险。如果我们现在新增了一个Unknown类并实现Result接口,用于表示未知的执行结果,但是忘记在getMsg()方法添加相应的条件分支编译器在这种情况下是不会提醒我们的,而是会在运行时候进入else条件里面,从而抛出异常并导致程序崩溃

当然,这种为了满足编译器的要求而编写无用条件分支的情况不仅在Kotlin当中存在,在Java或者是其他编程语言当中也普遍存在

不过好消息是,Kotlin密封类可以很好地解决这个问题,下面我们就来学习一下。

密封类的关键字sealed class,它的用法同样非常简单,我们可以轻松地将Result接口改造成密封类的写法

sealed class Result
class Success(val msg: String) : Result()
class Failure(val error: String) : Result()

fun getMsg(result: Result) = when (result) {
    is Success -> result.msg
    is Failure -> result.error
}

可以看到,代码并没有什么太大的变化,只是将interface关键字改成了sealed class。另外,由于密封类是一个可继承的类,因此在继承它的时候需要在后面加上一对括号

那么改成密封类之后有什么作用呢?你会发现现在getMsg()方法中的else条件已经不再需要了.

并且如果我们现在新增一个Unknown类,并也让它继承Result,此时getMsg()方法就一定会报错,必须增加一Unknown的条件分支才能让代码编译通过

这就是密封类主要的作用和使用方法了。另外再多说一句,密封类及其所有子类只能定义在同一个文件的顶层位置,不能嵌套在其他类中,这是被密封类底层的实现机制所限制的。

原文地址:https://blog.csdn.net/pengguichu/article/details/134727440

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_23616.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注