《Kotlin核心编程》 ——2.2 val和var的使用规则
2.2 val和var的使用规则
与Java另一点不同在于,Kotlin声明变量时,引入了val和var的概念。var很容易理解,JavaScript等其他语言也通过该关键字来声明变量,它对应的就是Java中的变量。那么val又代表什么呢?
如果说var代表了varible(变量),那么val可看成value(值)的缩写。但也有人觉得这样并不直观或准确,而是把val解释成varible+final,即通过val声明的变量具有Java中的final关键字的效果,也就是引用不可变。
我们可以在IntelliJ IDEA或Android Studio中查看val语法反编译后转化的Java 代码,从中可以很清楚地发现它是用final实现这一特性的。
2.2.1 val的含义:引用不可变
val的含义虽然简单,但依然会有人迷惑。部分原因在于,不同语言跟val相关的语言特性存在差异,从而容易导致误解。
我们先用val声明一个指向数组的变量,然后尝试对其进行修改。
>>> val x = intArrayOf(1, 2, 3)
>>> x = intArrayOf(2, 3, 4)
error: val cannot be reassigned
>>> x[0] = 2
>>> println(x[0])
2
因为引用不可变,所以x不能指向另一个数组,但我们可以修改x指向数组的值。
如果你熟悉Swift,自然还会联想到let,于是我们再把上面的代码翻译成Swift的版本。
let x = [1, 2, 3]
x = [2, 3, 4]
Swift:: Error: cannot assign to value: 'x' is a 'let' constant
x[0] = 2
Swift:: Error: cannot assign through subscript: 'x' is a 'let' constant
这下连引用数组的值都不能修改了,这是为什么呢?
其实根本原因在于两种语言对数组采取了不同的设计。在Swift中,数组可以看成一个值类型,它与变量x的引用一样,存放在栈内存上,是不可变的。而Kotlin这种语言的设计思路,更多考虑数组这种大数据结构的拷贝成本,所以存储在堆内存中。
因此,val声明的变量是只读变量,它的引用不可更改,但并不代表其引用对象也不可变。事实上,我们依然可以修改引用对象的可变成员。如果把数组换成一个Book类的对象,如下编写方式会变得更加直观:
class Book(var name: String) { // 用var声明的参数name引用可被改变
fun printName() {
println(this.name)
}
}
fun main(args: Array<String>) {
val book = Book("Thinking in Java") // 用val声明的book对象的引用不可变
book.name = "Diving into Kotlin"
book.printName() // Diving into Kotlin
}
首先,这里展示了Kotlin中的类不同于Java的构造方法,我们会在第3章中介绍关于它具体的语法。其次,我们发现var和val还可以用来声明一个类的属性,这也是Kotlin中一种非常有个性且有用的语法,你还会在后续的数据类中再次接触到它的应用。
- 点赞
- 收藏
- 关注作者
评论(0)