Kotlin 变量与常量 #

一、变量声明 #

1.1 val - 只读变量 #

val(value)声明只读变量,类似于 Java 的 final

kotlin
val name: String = "Kotlin"
val age = 25  // 类型推断

// 错误:不能重新赋值
// name = "Java"

1.2 var - 可变变量 #

var(variable)声明可变变量:

kotlin
var count: Int = 0
count = 10  // 正确:可以重新赋值

var message = "Hello"
message = "World"  // 正确

1.3 val vs var #

特性 val var
重新赋值 不可以 可以
引用可变 可以(对象内容可变) 可以
推荐程度 优先使用 需要时使用
kotlin
// val 引用不可变,但对象内容可变
val list = mutableListOf(1, 2, 3)
list.add(4)  // 正确:修改列表内容
// list = mutableListOf()  // 错误:不能重新赋值

二、类型推断 #

2.1 自动类型推断 #

Kotlin 可以根据初始值推断变量类型:

kotlin
val name = "Kotlin"      // 推断为 String
val age = 25             // 推断为 Int
val price = 99.99        // 推断为 Double
val isActive = true      // 推断为 Boolean

// 显式指定类型
val count: Long = 100
val score: Float = 95.5f

2.2 类型必须明确 #

没有初始值时必须指定类型:

kotlin
// 错误:无法推断类型
// val name

// 正确:显式指定类型
val name: String
name = "Kotlin"

三、声明位置 #

3.1 顶层变量 #

在类/函数外部声明:

kotlin
val APP_NAME = "MyApp"
var globalCounter = 0

fun main() {
    println(APP_NAME)
    globalCounter++
}

3.2 成员变量 #

在类中声明:

kotlin
class Person {
    val name: String = "Unknown"  // 只读属性
    var age: Int = 0              // 可变属性
}

3.3 局部变量 #

在函数中声明:

kotlin
fun calculate() {
    val a = 10
    var b = 20
    b = a + b
    return b
}

四、延迟初始化 #

4.1 lateinit #

用于 var 类型的延迟初始化:

kotlin
class MainActivity {
    // 延迟初始化,不需要立即赋值
    lateinit var name: String
    
    fun init() {
        name = "Kotlin"  // 在使用前初始化
    }
    
    fun printName() {
        // 检查是否已初始化
        if (::name.isInitialized) {
            println(name)
        }
    }
}

使用限制:

  • 只能用于 var
  • 不能用于基本类型(Int、Long、Float 等)
  • 不能用于可空类型
  • 必须在使用前初始化
kotlin
// 错误用法
// lateinit val name: String     // 错误:必须是 var
// lateinit var age: Int         // 错误:不能是基本类型
// lateinit var name: String?    // 错误:不能是可空类型

4.2 lazy #

用于 val 类型的延迟初始化:

kotlin
val heavyObject: HeavyClass by lazy {
    println("初始化...")
    HeavyClass()  // 第一次访问时才初始化
}

// 使用
println("开始")
println(heavyObject)  // 此时才初始化
println(heavyObject)  // 使用缓存值

lazy 特点:

  • 线程安全(默认)
  • 只初始化一次
  • 第一次访问时初始化
kotlin
// 指定线程模式
val data by lazy(LazyThreadSafetyMode.NONE) {
    loadData()
}

4.3 lateinit vs lazy #

特性 lateinit lazy
变量类型 var val
类型限制 非基本类型、非可空 无限制
初始化时机 手动控制 首次访问时
线程安全 是(默认)

五、常量 #

5.1 编译时常量 #

使用 const val 声明:

kotlin
const val MAX_COUNT = 100
const val APP_NAME = "MyApp"
const val PI = 3.14159

// 错误:const 只能用于顶层或 object 中
// class MyClass {
//     const val VALUE = 10  // 错误
// }

const 限制:

  • 只能用于顶层或 object
  • 只能是基本类型或 String
  • 必须在编译时确定值

5.2 普通常量 #

kotlin
// 普通常量(运行时常量)
val currentTime = System.currentTimeMillis()

// 编译时常量
const val VERSION = "1.0.0"

5.3 命名约定 #

常量使用全大写字母和下划线:

kotlin
const val MAX_SIZE = 100
const val DEFAULT_TIMEOUT = 30000L
const val API_BASE_URL = "https://api.example.com"

六、属性访问器 #

6.1 自定义 getter #

kotlin
val isEmpty: Boolean
    get() = this.size == 0

class Circle(val radius: Double) {
    val area: Double
        get() = Math.PI * radius * radius
}

val circle = Circle(5.0)
println(circle.area)  // 每次访问都计算

6.2 自定义 setter #

kotlin
class Person {
    var name: String = ""
        set(value) {
            field = value.trim()
        }
    
    var age: Int = 0
        set(value) {
            field = if (value >= 0) value else 0
        }
}

val person = Person()
person.name = "  Kotlin  "
println(person.name)  // "Kotlin"(已去除空格)

6.3 幕后字段 #

使用 field 关键字访问实际存储:

kotlin
class Counter {
    var count = 0
        get() = field
        set(value) {
            if (value >= 0) {
                field = value
            }
        }
}

七、类型别名 #

使用 typealias 创建类型别名:

kotlin
typealias UserMap = Map<String, User>
typealias Predicate<T> = (T) -> Boolean
typealias ClickHandler = (View) -> Unit

// 使用
val users: UserMap = mapOf()
val isAdult: Predicate<Person> = { it.age >= 18 }

八、变量作用域 #

8.1 作用域规则 #

kotlin
val globalVar = 100

fun outer() {
    val outerVar = 200
    
    fun inner() {
        val innerVar = 300
        println(globalVar)   // 可访问
        println(outerVar)    // 可访问
        println(innerVar)    // 可访问
    }
}

8.2 变量遮蔽 #

kotlin
val count = 10

fun test() {
    val count = 20  // 遮蔽外部变量
    println(count)  // 输出 20
    
    if (true) {
        val count = 30  // 遮蔽函数级变量
        println(count)  // 输出 30
    }
    
    println(count)  // 输出 20
}

九、最佳实践 #

9.1 优先使用 val #

kotlin
// 推荐
val name = "Kotlin"
val items = listOf(1, 2, 3)

// 只在需要时使用 var
var counter = 0
counter++

9.2 使用有意义的名称 #

kotlin
// 不推荐
val n = "Kotlin"
val a = 25

// 推荐
val name = "Kotlin"
val age = 25

9.3 延迟初始化选择 #

kotlin
// val 延迟初始化 → 使用 lazy
val database: Database by lazy { Database.connect() }

// var 延迟初始化 → 使用 lateinit
lateinit var service: ApiService

9.4 避免全局可变变量 #

kotlin
// 不推荐
var globalCounter = 0

// 推荐:使用封装
object Counter {
    private var _count = 0
    val count: Int get() = _count
    
    fun increment() = _count++
}

十、总结 #

变量与常量要点:

关键字 用途 特点
val 只读变量 引用不可变,优先使用
var 可变变量 引用可变,谨慎使用
const val 编译时常量 编译时确定值
lateinit 延迟初始化 用于 var,非基本类型
lazy 懒加载 用于 val,首次访问初始化

下一步,让我们学习 基本数据类型

最后更新:2026-03-27