1 类型推导
在Java 中如果想要定义一个变量,需要在变量名前面声明这个变量的类型,比如说int a 表示a 是一个整型变量,String b 表示b 是一个字符串变量。而Kotlin 中定义一个变量,只允许在变量前声明两种关键字——val 和 var ,类型通常在变量名的后面:
val a: Int = 10
val s: String = "I am Kotlin"
注意,Kotlin 每一行代码的结尾是不用加分号的。
为什么要采用这种风格呢?以下是Kotlin 官方FAQ 的回答:我们相信这样可以使得代码的可读性更好。同时,这也有利于使用一些良好的语法特性,比如省略类型声明(Scala 的经验表明,这不是一个错误的选择)。
关于“省略类型声明”的描述,是什么意思呢?为什么仅仅使用val 或者var 来声明一个变量,编译器就知道这个变量是什么类型呢?这也是Kotlin 比较有特色的一点,它拥有出色的类型推导机制,是Kotlin 在Java 基础上增强的语言特性之一。通俗地理解,编译器可以在不显式声明类型的情况下,自动推导出它所需要的类型:
val string = "I am Kotlin"
val int = 1314
val long = 1314L
val float = 13.14F
val double = 13.14
val double2 = 10e6
println(string.javaClass.name)
类型推导在很大程度上提高了Kotlin 这种静态类型语言的开发效率。
但是Kotlin 的类型推导机制并不总是可以正常工作的,如果对一个变量延迟赋值的话,Kotlin 就无法自动推导它的类型了。 这时候就需要显式地声明变量类型才行:
代码如下所示:
val s: String
显式地声明了变量s 为String 类型,此时Kotlin 就不会再尝试进行类型推导了。如果现在尝试将一个整形赋值给s ,那么编译器就会抛出类型不匹配的异常:
另外,Kotlin 中Int 的首字母是大写的,而Java 中int 的首字母是小写的。这表示Kotlin 完全抛弃了Java 中的基本数据类型,全部使用了对象数据类型。在Java 中int 是关键字,而在Kotlin 中Int 变成了一 个类,它拥有自己的方法和继承结构。
下图中列出了Java 中的每一个基本数据类型在Kotlin 中对应的对象数据类型:
2 val 和var
与Java 另一点不同在于,Kotlin 声明变量时,引入了val 和var 的概念:
var (variable ):引用可变,这种变量在初始赋值之后仍然可以再被重新赋值;val (variable + final ):引用不可变,这种变量在初始赋值之后就再也不能重新赋值,具有Java 中的final 关键字的效果;
variable [?veri?bl??v?ri?bl] 可变的
用val 声明一个Int 类型的变量a ,尝试对变量a 修改:
val a = 10
a = a * 10
编译器会提示一个错误:
然后用val 声明一个指向数组的变量,然后尝试对其进行修改:
val x = intArrayOf(1, 2, 3)
x = intArrayOf(2, 3, 4)
编译器提示错误:
如果,对其中的某个元素进行修改:
val x = intArrayOf(1, 2, 3)
x[0] = 4
println("x[0] = ${x[0]}")
因为引用不可变,所以x 不能指向另一个数组,但可以修改x 指向数组的值。
val 声明的变量是只读变量,它的引用不可更改,但并不代表其引用对象也不可变。 如果把数组换成一个Book 类的对象,如下编写方式会变得更加直观:
class Book(var name: String) {
fun printName() {
println(this.name)
}
}
fun main() {
val book = Book("Thinking in Java")
book.name = "Diving into Kotlin"
book.printName()
}
val 关键字用来声明一个引用不可变的变量,而var 关键字用来声明一个引用可变的变量如下所示:
var a = 10
a = a * 10
println("a = $a")
var x = intArrayOf(1, 2, 3)
x = intArrayOf(2, 3, 4)
既然val 关键字有这么多的束缚,为什么还要用这个关键字呢?全部用var 关键字不就好了。其实Kotlin 之所以这样设计,是为了解决Java 中final 关键字没有被合理使用的问题。
在Java 中,除非主动在变量前声明了final 关键字,否则这个变量就是可变的。然而这并不是一件好事,当项目变得越来越复杂,参与开发的人越来越多时,不知道什么时候一个可变的变量就被修改了,即使它原本不应该被修改,这就经常会导致出现一些很难排查的问题。因此,一个好的编程习惯是,除非一个变量明确允许被修改,否则都应该给它加上final 关键字。
不难发现副作用的产生往往与可变数据及共享状态有关, 有时候它会使得结果变得难以预测。比如,我们在采用多线程处理高并发的场景,“并发访问”就是一个明显的例子。
因此,Kotlin 在设计的时候就采用了和Java 完全不同的方式,提供了val 和var 这两个关键字,必须由开发者主动声明该变量是可变的还是不可变的。
在很多Kotlin 的学习资料中,都会传递一个原则:优先使用val 来声明变量。
- 这是一种防御性的编码思维模式,更加安全和可靠,因为变量的值永远不会在其他地方被修改(一些框架采用反射技术的情况除外);
- 不可变的变量意味着更加容易推理,越是复杂的业务逻辑,它的优势就越大;
|