你真的完全搞懂了var和val的区别及其在编程中的具体应用吗?
- 内容介绍
- 文章标签
- 相关推荐
提到现代 JVM 语言,var 与 val 总是交叉出现。它们看似只是一对关键词,却暗藏着「引用能否重新指向」与「对象本身是否可以改变」的细微差别。本文不打算给出枯燥的定义, 而是从实际开发场景出发,用生动的例子和情感化的描述,帮你彻底拆解这两个关键字背后的概念。
:理解 `var` 和 `val` 的核心差异
Kotlin 与 Java 为我们提供了两套看似相似却细节截然不同的关键词体系。真正弄清楚它们背后的语义——「只能够一次赋值」vs 「只能够读取一次」「只能够指向同一实例」vs 「实例内容仍可自由玩耍」,才能够在日常编码中游刃有余。记住一句简单的话:「用 `val` 锁定你的意图,用 `var` 放飞你的需求。」当这句话扎根于你的思考方式,你就已经把表面上的语法差异升华为设计哲学了,也是醉了...。
var可变性与动态变化
var 用来声明「可以赋值」的变量;只有在代 一句话。 码中明确使用var声明的变量才能被重新赋值。
// 可变引用var counter = 0counter = counter + 1 // 随时可以改变// 只读引用val name = "Kotlin"// name = "Java" // 编译错误:不能赋值
val常量性与不变性
val 则声明「只能赋一次」的引用。这里需要特别强调:val并不等同于「不可变对象」,它仅保证引用本身不再改变,躺平。。
// 可变引用var counter = 0counter = counter + 1 // 可以修改counter的值// 只读引用val name = "Kotlin"// name = "Java" //编译错误:不能重新赋值
“Lombok 的 @Val 与 Kotlin 的 `val` 完全一样”?
换位思考... Lombok 的 @Val 其实吧是对局部 final 的语法糖, 它并不会影响属性生成 getter/setter行为,也没有 Kotlin 那种智能转换机制。
`val` 和 `var` 的特性
val 的智能转换:减少冗余代码
Kotlin能够确认某个val在当前作用域不会被重新赋值后把它视作具体子类型, 摆烂... 从而省去显式强转。比方说:
fun printLength { if { println } } printLength // 输出 Hello.length printLength // 无输出 若改用var o 编译器必须每次访问前dou检查是否已经转型成功,导致额外检查开销。
`const val`:编译期常量——性能优化利器
Kotlin 在顶层或 object 中允许使用const val声明真正意义上的常量。编译器会在字节码层面将其值直接内联到使用处,从而省去一次字段读取。
const val MAX_RETRY = 5 //编译后所有MAX_RETRY值都会被替换成数字5 // 在运行时直接使用5而非读取字段值更高效! fun someFunction { println } const val MAX_RETRY = someFunction //可以在 const val 定义时进行计算! 但是只能在一个作用域内完成! 如果超出范围会报错! 主要原因是编译器会在编译时就确定其值! const val MAX_RETRY : Int = calculateRetryCount //只能在定义的时候做计算!无法动态获取数据! 如果想要动态获取数据的话就不要使用 const val ! 要用普通值 或者 lazy value !
`const val` 的零成本特性
哭笑不得。 `const val` 在字节码里根本不存在字段, 它们直接成为字面量;相较之下普通val 会产生一次字段读取,即使是 final静态字段也要走一次 getstatic 指令。
`var` 的 setter 开销
稳了! `var` 会自动生成 getter/setter ,每次写操作dou会走一次 set 方法。如果频繁修改,同样会带来微小但累计可观的调用成本。
“把所有东西都写成 `val`”?合理权衡是关键
虽然倾向使用只读Ke以提升平安性, 但过度限制会导致代码必须频繁创建新对象,反而影响性能和可维护性。合理权衡才是王道。
自定义 Getter:让 `val` 等同于拥有特定逻辑的属性
Kotlin 支持为属性提供专属的读取逻辑、这意味着每次访问dou可能得到不同的后来啊:,换言之...
const val MAX_RETRY = 5 //编译后所有MAX_RETRY值都会被替换成数字5 fun getRetryLimit: Int { return calculateRetryLimit } val retryLimit: Int get = getRetryLimit //每次访问retryLimit都施行getRetryLimit fun getRetryLimit:Int{return calculateRetryLimit} const val MAX_RETRY : Int=getRetryLimit; //可以使用函数实现!但是要注意函数调用的开销!! 如果函数调用比较复杂的话可能会导致性能问题! 所以要慎重选择!注意避免死循环!!
“自定义 Getter 会让属性自动成为 const”?
自定义 Getter 本质上是方法 , 每次调用dou可能施行计算 ,所以呢根本无法进行 compile‑time 常量优化 ,物超所值。。
性Neng角度下 `var / val` 有什么区别?
Smart Cast :提升代码简洁性
`Val`的优势在于其智能类型转换能力 。编译器可以根据上下文推断出变量的具体类型 ,无需手动进行类型转换 。这大大简化了代码 ,减少了冗余 。比方说:如果一个` Val表示的是一个String 类型的值 ,那么在后续的代码中 ,编译器会自动将它视为String 类型 。 翻车了。 而对于` Var则需要手动进行类型转换 ,这可能会增加代码的复杂性和出错的可能性 。
kotlin fun processValue{ if { println println } else{ println } } processValue processValue零成本常量 :提高运行效率
`Const Val具有零成本常量的特点 。这意味着编译器会将常量的具体值直接嵌入到程序中 ,而不是像普通变量那样需要额外的内存空间来存储值的地址 。这大大提高了程序的运行效率 ,特别是在处理大量重复计算时效果更加明显 。 `Setter 开销的影响:优化性能的关键
`Var类型的变量在使用过程中会涉及 setter 方法 ,每次修改变量的值都需要调用 setter 方法来实现 。而对于 `Val类型的变量则没有 setter 方法 ,这意味着其值一旦被初始化后就无法再被修改 。这种设计不仅可以提高程序的平安性 ,还可以减少不必要的内存开销和性能损耗 。 `最佳实践建议
- 首选 使用 read‑only reference `'val'` 来声明所有不需要重新指向的数据;只有当业务明确要求“随时能够指向另一个实例”时才用 mutable reference `'var'`。
- 利用 `const val` 定义硬编码配置、 协议版本号等 ,在发布包体积和运行效率上都有好处。
- 避免在公开 API 上暴露可变 `public var` , 否则外部调用者可以随意内部状态 ,引发难以追踪的 bug。
提到现代 JVM 语言,var 与 val 总是交叉出现。它们看似只是一对关键词,却暗藏着「引用能否重新指向」与「对象本身是否可以改变」的细微差别。本文不打算给出枯燥的定义, 而是从实际开发场景出发,用生动的例子和情感化的描述,帮你彻底拆解这两个关键字背后的概念。
:理解 `var` 和 `val` 的核心差异
Kotlin 与 Java 为我们提供了两套看似相似却细节截然不同的关键词体系。真正弄清楚它们背后的语义——「只能够一次赋值」vs 「只能够读取一次」「只能够指向同一实例」vs 「实例内容仍可自由玩耍」,才能够在日常编码中游刃有余。记住一句简单的话:「用 `val` 锁定你的意图,用 `var` 放飞你的需求。」当这句话扎根于你的思考方式,你就已经把表面上的语法差异升华为设计哲学了,也是醉了...。
var可变性与动态变化
var 用来声明「可以赋值」的变量;只有在代 一句话。 码中明确使用var声明的变量才能被重新赋值。
// 可变引用var counter = 0counter = counter + 1 // 随时可以改变// 只读引用val name = "Kotlin"// name = "Java" // 编译错误:不能赋值
val常量性与不变性
val 则声明「只能赋一次」的引用。这里需要特别强调:val并不等同于「不可变对象」,它仅保证引用本身不再改变,躺平。。
// 可变引用var counter = 0counter = counter + 1 // 可以修改counter的值// 只读引用val name = "Kotlin"// name = "Java" //编译错误:不能重新赋值
“Lombok 的 @Val 与 Kotlin 的 `val` 完全一样”?
换位思考... Lombok 的 @Val 其实吧是对局部 final 的语法糖, 它并不会影响属性生成 getter/setter行为,也没有 Kotlin 那种智能转换机制。
`val` 和 `var` 的特性
val 的智能转换:减少冗余代码
Kotlin能够确认某个val在当前作用域不会被重新赋值后把它视作具体子类型, 摆烂... 从而省去显式强转。比方说:
fun printLength { if { println } } printLength // 输出 Hello.length printLength // 无输出 若改用var o 编译器必须每次访问前dou检查是否已经转型成功,导致额外检查开销。
`const val`:编译期常量——性能优化利器
Kotlin 在顶层或 object 中允许使用const val声明真正意义上的常量。编译器会在字节码层面将其值直接内联到使用处,从而省去一次字段读取。
const val MAX_RETRY = 5 //编译后所有MAX_RETRY值都会被替换成数字5 // 在运行时直接使用5而非读取字段值更高效! fun someFunction { println } const val MAX_RETRY = someFunction //可以在 const val 定义时进行计算! 但是只能在一个作用域内完成! 如果超出范围会报错! 主要原因是编译器会在编译时就确定其值! const val MAX_RETRY : Int = calculateRetryCount //只能在定义的时候做计算!无法动态获取数据! 如果想要动态获取数据的话就不要使用 const val ! 要用普通值 或者 lazy value !
`const val` 的零成本特性
哭笑不得。 `const val` 在字节码里根本不存在字段, 它们直接成为字面量;相较之下普通val 会产生一次字段读取,即使是 final静态字段也要走一次 getstatic 指令。
`var` 的 setter 开销
稳了! `var` 会自动生成 getter/setter ,每次写操作dou会走一次 set 方法。如果频繁修改,同样会带来微小但累计可观的调用成本。
“把所有东西都写成 `val`”?合理权衡是关键
虽然倾向使用只读Ke以提升平安性, 但过度限制会导致代码必须频繁创建新对象,反而影响性能和可维护性。合理权衡才是王道。
自定义 Getter:让 `val` 等同于拥有特定逻辑的属性
Kotlin 支持为属性提供专属的读取逻辑、这意味着每次访问dou可能得到不同的后来啊:,换言之...
const val MAX_RETRY = 5 //编译后所有MAX_RETRY值都会被替换成数字5 fun getRetryLimit: Int { return calculateRetryLimit } val retryLimit: Int get = getRetryLimit //每次访问retryLimit都施行getRetryLimit fun getRetryLimit:Int{return calculateRetryLimit} const val MAX_RETRY : Int=getRetryLimit; //可以使用函数实现!但是要注意函数调用的开销!! 如果函数调用比较复杂的话可能会导致性能问题! 所以要慎重选择!注意避免死循环!!
“自定义 Getter 会让属性自动成为 const”?
自定义 Getter 本质上是方法 , 每次调用dou可能施行计算 ,所以呢根本无法进行 compile‑time 常量优化 ,物超所值。。
性Neng角度下 `var / val` 有什么区别?
Smart Cast :提升代码简洁性
`Val`的优势在于其智能类型转换能力 。编译器可以根据上下文推断出变量的具体类型 ,无需手动进行类型转换 。这大大简化了代码 ,减少了冗余 。比方说:如果一个` Val表示的是一个String 类型的值 ,那么在后续的代码中 ,编译器会自动将它视为String 类型 。 翻车了。 而对于` Var则需要手动进行类型转换 ,这可能会增加代码的复杂性和出错的可能性 。
kotlin fun processValue{ if { println println } else{ println } } processValue processValue零成本常量 :提高运行效率
`Const Val具有零成本常量的特点 。这意味着编译器会将常量的具体值直接嵌入到程序中 ,而不是像普通变量那样需要额外的内存空间来存储值的地址 。这大大提高了程序的运行效率 ,特别是在处理大量重复计算时效果更加明显 。 `Setter 开销的影响:优化性能的关键
`Var类型的变量在使用过程中会涉及 setter 方法 ,每次修改变量的值都需要调用 setter 方法来实现 。而对于 `Val类型的变量则没有 setter 方法 ,这意味着其值一旦被初始化后就无法再被修改 。这种设计不仅可以提高程序的平安性 ,还可以减少不必要的内存开销和性能损耗 。 `最佳实践建议
- 首选 使用 read‑only reference `'val'` 来声明所有不需要重新指向的数据;只有当业务明确要求“随时能够指向另一个实例”时才用 mutable reference `'var'`。
- 利用 `const val` 定义硬编码配置、 协议版本号等 ,在发布包体积和运行效率上都有好处。
- 避免在公开 API 上暴露可变 `public var` , 否则外部调用者可以随意内部状态 ,引发难以追踪的 bug。

