文章目录
- 一、报错信息
- 二、问题分析
- 三、解决方案
该问题的本质就是 , 成员属性 在 init 初始化代码块中进行初始化 , 但是在初始化之前调用了该 成员属性 , 编译时没有报错信息 , 但是运行时会报异常 ;
一、报错信息
执行如下代码 :
class Hello {var name: Stringfun nameFirstLetter() = name[0]init {println(nameFirstLetter())name = "Tom"}
}fun main() {Hello()
}
执行结果 :
Exception in thread "main" java.lang.NullPointerExceptionat Hello.nameFirstLetter(Hello.kt:3)at Hello.<init>(Hello.kt:5)at HelloKt.main(Hello.kt:11)at HelloKt.main(Hello.kt)Process finished with exit code 1
上述代码在编译时 , 没有报错 ;
二、问题分析
从 初始化 角度分析 上述代码的执行顺序 , Kotlin 类 对象在实例化 时会执行一系列的 初始化操作 , 这些操作按照如下顺序执行 :
- 主构造函数 中属性赋值
- 类中的属性赋值
- init 初始化块 中的代码执行
- 次构造函数 中的代码执行
首先 , 上述代码中没有主构造 函数 , 因此该项忽略 ;
然后 , 执行属性的赋值 , 代码中定义了 name 属性 , 但是没有进行赋值 ;
var name: String
再后 , 执行 init 初始化块 , 其中先执行 nameFirstLetter
函数 , 在该函数中调用了 fun nameFirstLetter() = name[0]
中的 name 属性 , 但是 name 属性还没有赋值 , 因此爆出了空指针异常 ;
init {println(nameFirstLetter())name = "Tom"}
该问题的本质就是 , 成员属性 在 init 初始化代码块中进行初始化 , 但是在初始化之前调用了该 成员属性 , 编译时没有报错信息 , 但是运行时会报异常 ;
三、解决方案
调换 初始化代码块 中的代码顺序 , 先给 name 成员赋值 , 然后再执行 调用 name 成员的方法 ;
class Hello{var name: Stringfun nameFirstLetter() = name[0]init {name = "Tom"println(nameFirstLetter())}
}fun main() {Hello()
}