Kotlin(二)—— 变量

1 类型推导

Java中如果想要定义一个变量,需要在变量名前面声明这个变量的类型,比如说int a表示a是一个整型变量,String b表示b是一个字符串变量。Kotlin中定义一个变量,只允许在变量前声明两种关键字——valvar,类型通常在变量名的后面:

val a: Int = 10
val s: String = "I am Kotlin"

注意,Kotlin每一行代码的结尾是不用加分号的。

为什么要采用这种风格呢?以下是Kotlin官方FAQ的回答:我们相信这样可以使得代码的可读性更好。同时,这也有利于使用一些良好的语法特性,比如省略类型声明(Scala的经验表明,这不是一个错误的选择)。

关于“省略类型声明”的描述,是什么意思呢?为什么仅仅使用val或者var来声明一个变量,编译器就知道这个变量是什么类型呢?这也是Kotlin比较有特色的一点,它拥有出色的类型推导机制,是KotlinJava基础上增强的语言特性之一。通俗地理解,编译器可以在不显式声明类型的情况下,自动推导出它所需要的类型:

val string = "I am Kotlin"  // java.lang.String
val int = 1314 // int
val long = 1314L // long
val float = 13.14F // float
val double = 13.14 // double
val double2 = 10e6 // double

println(string.javaClass.name)

类型推导在很大程度上提高了Kotlin这种静态类型语言的开发效率。

但是Kotlin的类型推导机制并不总是可以正常工作的,如果对一个变量延迟赋值的话,Kotlin就无法自动推导它的类型了。 这时候就需要显式地声明变量类型才行:

显式声明类型

代码如下所示:

val s: String

显式地声明了变量sString类型,此时Kotlin就不会再尝试进行类型推导了。如果现在尝试将一个整形赋值给s,那么编译器就会抛出类型不匹配的异常:

Kotlin(二)—— 变量_第1张图片

另外,KotlinInt的首字母是大写的,而Javaint的首字母是小写的。这表示Kotlin完全抛弃了Java中的基本数据类型,全部使用了对象数据类型。在Javaint是关键字,而在KotlinInt变成了一 个类,它拥有自己的方法和继承结构。

下图中列出了Java中的每一个基本数据类型在Kotlin中对应的对象数据类型:

Kotlin(二)—— 变量_第2张图片

2 valvar

Java另一点不同在于,Kotlin声明变量时,引入了valvar的概念:

  • varvariable):引用可变,这种变量在初始赋值之后仍然可以再被重新赋值;
  • valvariable + final):引用不可变,这种变量在初始赋值之后就再也不能重新赋值,具有Java中的final关键字的效果;

variable [ˈveriəblˌˈværiəbl] 可变的

val声明一个Int类型的变量a,尝试对变量a修改:

val a = 10
a = a * 10

编译器会提示一个错误:

Kotlin(二)—— 变量_第3张图片

然后用val声明一个指向数组的变量,然后尝试对其进行修改:

val x = intArrayOf(1, 2, 3)
x = intArrayOf(2, 3, 4)

编译器提示错误:

Kotlin(二)—— 变量_第4张图片

如果,对其中的某个元素进行修改:

val x = intArrayOf(1, 2, 3)
x[0] = 4
println("x[0] = ${x[0]}") // x[0] = 4

因为引用不可变,所以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() // Diving into Kotlin
}

val关键字用来声明一个引用不可变的变量,而var关键字用来声明一个引用可变的变量如下所示:

var a = 10
a = a * 10
println("a = $a") // a = 100

var x = intArrayOf(1, 2, 3)
x = intArrayOf(2, 3, 4)

既然val关键字有这么多的束缚,为什么还要用这个关键字呢?全部用var关键字不就好了。其实Kotlin之所以这样设计,是为了解决Javafinal关键字没有被合理使用的问题。

Java中,除非主动在变量前声明了final关键字,否则这个变量就是可变的。然而这并不是一件好事,当项目变得越来越复杂,参与开发的人越来越多时,不知道什么时候一个可变的变量就被修改了,即使它原本不应该被修改,这就经常会导致出现一些很难排查的问题。因此,一个好的编程习惯是,除非一个变量明确允许被修改,否则都应该给它加上final关键字。

不难发现副作用的产生往往与可变数据及共享状态有关, 有时候它会使得结果变得难以预测。比如,我们在采用多线程处理高并发的场景,“并发访问”就是一个明显的例子。

因此,Kotlin在设计的时候就采用了和Java完全不同的方式,提供了valvar这两个关键字,必须由开发者主动声明该变量是可变的还是不可变的。

在很多Kotlin的学习资料中,都会传递一个原则:优先使用val来声明变量。

  • 这是一种防御性的编码思维模式,更加安全和可靠,因为变量的值永远不会在其他地方被修改(一些框架采用反射技术的情况除外);
  • 不可变的变量意味着更加容易推理,越是复杂的业务逻辑,它的优势就越大;

你可能感兴趣的:(kotlin,java,scala)