一、变量声明:val / var
1. 核心区分
| 关键字 | 含义 | 可否重新赋值 | 对应Java |
|---|---|---|---|
val |
只读变量(不可变引用) | ❌ 不能重新赋值(引用不变,对象内部属性可修改) |
final 变量 |
var |
可变变量(可变引用) | ✅ 支持重新赋值 | 普通非final变量 |
2. 语法格式
// 方式1:类型自动推导(推荐)
val name = "Kotlin"
var age = 20
// 方式2:显式声明类型,冒号分隔
val name: String = "Kotlin"
var age: Int = 20
// ❌ 错误:声明变量不赋值且不指定类型,无法推导
// val a
// ✅ 声明不立即赋值,必须显式标注类型
val a: Int
a = 10
编码规范:优先使用
val,只有需要修改时才用var
3. 易错点:val ≠ 对象不可变
class Person(var name: String)
fun main() {
val p = Person("Tom")
p.name = "Jack" // ✅ 允许!val只是引用不能变,对象内部可变
// p = Person("Lisa") ❌ 禁止重新赋值引用
}
二、延迟初始化 / 懒初始化
1. lateinit var 延迟初始化(只能 var,非空、不能基础类型Int/String)
适用场景:变量声明时无法赋值,后续一定会初始化,避免空安全 ?
lateinit var text: String
fun init() {
text = "hello"
}
// 判断是否完成初始化
if(::text.isInitialized){
println(text)
}
限制:
- 不能用于
val - 不支持基础数据类型(
Int、Boolean等) - 不能赋值为 null
2. by lazy 懒加载(只能 val,首次访问才执行初始化)
线程安全默认同步,适合开销大的对象
val data: String by lazy {
println("执行初始化")
"加载完成"
}
fun main() {
println("start")
println(data) // 首次访问执行lambda
println(data) // 直接返回缓存值,不再执行
}
三种模式:
// 默认:SYNCHRONIZED 多线程单例
val v1 by lazy { ... }
// PUBLICATION 多线程允许多次创建,返回最先完成的值
val v2 by lazy(LazyThreadSafetyMode.PUBLICATION){...}
// NONE 不加同步,单线程环境使用,性能最高
val v3 by lazy(LazyThreadSafetyMode.NONE){...}
对比记忆
-
lateinit var:随时手动赋值;var、运行时赋值、无法缓存 -
by lazy:首次读取自动初始化;val、懒加载、自带缓存
三、空安全相关变量
var str: String? = null // 可空类型,必须加 ?
str = "test"
// 安全调用
str?.length
// 非空断言(慎用,空时抛异常)
str!!.length
四、对象初始化(类实例创建)
1. 基础构造器创建对象
Kotlin 不需要 new 关键字
class Person(name: String) // 主构造函数
// 对象实例化
val p = Person("张三")
2. 主构造函数 + 属性简写(高频写法)
直接在构造器声明属性,省去单独赋值
// name只读,age可变
class User(val name: String, var age: Int)
val u = User("李四", 22)
println(u.name)
u.age = 23
3. 初始化块 init{}
主构造函数执行时同步执行,多个 init 按顺序执行
class User(val name: String) {
init {
println("初始化块执行,name=$name")
}
}
4. 次构造函数 constructor
class User(val name: String) {
constructor() : this("默认名称"){
// 次构造逻辑
}
}
val u = User()
5. 匿名对象(Object)
// 单次使用匿名对象
val obj = object {
val msg = "匿名对象"
}
println(obj.msg)
// 继承场景
val runnable = object : Runnable {
override fun run() {}
}
五、常见初始化模式汇总示例
class Student(val id: Int) {
// 普通立即初始化
val school = "大学"
var score = 0
// 懒加载
val info: String by lazy { "学生ID:$id" }
// 延迟初始化
lateinit var address: String
init {
println("Student 初始化块 id=$id")
}
}
fun main() {
val s = Student(1001)
s.address = "深圳"
println(s.info)
}
六、面试高频区分小结
-
val:引用不可变;var:引用可变 -
lateinit var:运行时手动赋值,不支持基础类型、val -
by lazy:读取时初始化,val专用,缓存结果 - 对象创建无
new;主构造参数添加val/var自动成为类成员 -
init{}在主构造调用阶段执行,早于次构造函数