上一篇:Kotlin一步一步学(二) -- 标准函数和静态方法
延迟初始化
如果你的类中存在很多全局变量时,为了保证它们能通过Kotlin的空指针检查语法,你不得不做许多的非空判断才行,即使你非常确定它们不会为空。那么这个问题有没办法解决?答案是肯定的,那就是对全局变量进行延迟初始化。
延迟初始化就是在变量声明前使用lateinit
关键字,它可以告诉Kotlin编译器,我会在晚些时候对这个变量进行初始化,然后就不用在一开始的时候将它赋值为null,并且不用在调用的地方做非空的判断。
原始的写法
class MainActivity : AppCompatActivity(), View.OnClickListener {
private var adapter: MyAdapter? = null //没有进行初始化,类型后面必须加一个?,并且赋值为null
override fun onCreate(savedInstanceState: Bundle?) {
...
adapter = Mydapter(mylist)
}
override fun onClick(v: View?) {
...
adapter?.notifyItemInserted(mylist.size - 1) //调用adapter的时候要进行判空
}
}
lateinit延迟初始化写法
class MainActivity : AppCompatActivity(), View.OnClickListener {
private lateinit var adapter: MyAdapter //使用lateinit进行延迟初始化声明,不需要赋值为null
override fun onCreate(savedInstanceState: Bundle?) {
...
adapter = Mydapter(mylist)
}
override fun onClick(v: View?) {
...
adapter.notifyItemInserted(mylist.size - 1) //调用adapter的时候不需要进行判空
}
}
当你对一个全局变量使用了lateinit关键字时,请一定要确保它在被任何调用前已经完成了初始化,否则程序就会抛出UninitializedPropertyAccessException
异常。
我们可以API来判断一个全局变量是否已经完成了初始化,这样可以避免报错和重复对某个变量进行初始化。对上面示例进行优化
class MainActivity : AppCompatActivity(), View.OnClickListener {
private lateinit var adapter: MyAdapter //使用lateinit进行延迟初始化声明,不需要赋值为null
override fun onCreate(savedInstanceState: Bundle?) {
...
if (!::adapter.isInitialized) //判断adapter是否已经初始化
adapter = Mydapter(mylist)
}
}
密封类
密封类用来表示受限的类继承结构:当一个值为有限几种的类型、而不能有任何其他类型时。在某种意义上,他们是枚举类的扩展:枚举类型的值集合也是受限的,但每个枚举常量只存在一个实例,而密封类的一个子类可以有可包含状态的多个实例。
要声明一个密封类,需要在类名前面添加 sealed 修饰符。虽然密封类也可以有子类,但是所有子类都必须在与密封类自身相同的文件中声明。
sealed class Result
class Success(val msg: String) : Result()
class Failure(val error : Exception) : Result()
使用密封类的关键好处在于使用when
表达式的时候,如果验证语句覆盖了所有情况,就不需要为该语句再添加一个 else
子句了。
fun getResult(result: Result) : String = when(expr) {
is Success -> result.msg
is Failure -> "Error is ${result.error.message}"
// 不再需要 else 子句,因为我们已经覆盖了所有的情况
}
sealed经常用于在adapter中和viewHolder一起使用,达到简化adapter代码的效果。
下一篇:一步一步学(四)