Kotlin Reference: Basic Types

  本系列翻译自 Kotlin 官方文档,并对一些疑难点添加了备注,以【注】标记。

  Kotlin 中一切皆对象,也就是说,我们可以调用任意变量的成员函数和属性。虽然一些内置类型的实现经过了优化,但对用户来说,它们仍表现为普通的类,本节就描述了这些类型:数字、字符、布尔和数组。

Numbers

  Kotlin 对数字的处理和 Java 类似,但又不完全相同。比如说,Kotlin 不会对数字进行隐式的扩大转换,字面值的表现也有不同。

  Kotlin 提供了以下表示数字的内置类型(这一点和 Java 类似):

类型 位宽
Double 64
Float 32
Long 64
Int 32
Short 16
Byte 8

  注意 Kotlin 中的字符不是数字。

## Literal Constants

  以下方法都可以用来表示整形字面常量:

  • 十进制:123
    • 长整形以大写的 L 结尾:123L
  • 十六进制:0x0F
  • 二进制:0b00001011

注意:Kotlin 不支持八进制字面值。

  Kotlin 也支持传统的浮点数字表示方法:

  • 默认为双精度:123.5123.5e10
  • 单精度浮点以 fF 结尾:123.5f

Underscores in numeric literals (since 1.1)

  可以在数字字面值中插入下划线来提高可读性,如:

[code lang=”kotlin”]val oneMillion = 1_000_000
val creditCardNumber = 1234_5678_9012_3456L
val socialSecurityNumber = 999_99_9999L
val hexBytes = 0xFF_EC_DE_5E
val bytes = 0b11010010_01101001_10010100_10010010[/code]

Representation

  在 Java 平台上,数值类型以 JVM 基本类型(Primitive Type)的形式存储。当引入可为空(Nullable)的数值引用(如 Int?)或泛型时,数值类型会被装箱(Boxing)。

  注意装箱后的数值不一定会保持一致(Identity):

[code lang=”kotlin”]val a: Int = 10000
print(a === a) // Prints ‘true’
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA === anotherBoxedA) // !!!Prints false!!![/code]

但会保持相等性(Equality):

[code lang=”kotlin”]val a: Int = 10000
print(a == a) // Prints ‘true’
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA == anotherBoxedA) // Prints ‘true'[/code]

【注】Kotlin 中,=== 检查的是引用的等同性,即检查两个引用是否指向同一个对象;== 检查的是结构的等同性,即检查 equals()。更多信息可参考 相等性

Explicit Conversions

  由于采用了不同的表示方法,较小的类型不是较大类型的子类,否则就会有下面的问题:

[code lang=”kotlin”]// Hypothetical code, does not actually compile:
val a: Int? = 1 // A boxed Int (java.lang.Integer)
val b: Long? = a // implicit conversion yields a boxed Long (java.lang.Long)
print(a == b) // Surprise! This prints “false” as Long’s equals() check for other part to be Long as well[/code]

由此导致的结果是,相等性也悄悄地被破坏了。

  因此,较小的类型不会隐式地转换为较大的类型。这意味着,我们不能直接把一个 Byte 类型的值赋给一个 Int 类型的变量:

[code lang=”kotlin”]val b: Byte = 1 // OK, literals are checked statically
val i: Int = b // ERROR[/code]

但可以通过显式地转换来扩展数值的范围:

[code lang=”kotlin”]val i: Int = b.toInt() // OK: explicitly widened[/code]

  所有数值类型都提供了如下的转换方法:

  • toByte(): Byte
  • toShort(): Short
  • toInt(): Int
  • toLong(): Long
  • toFloat(): Float
  • toDouble(): Double
  • toChar(): Char

  缺乏隐式转换并不会带来明显的问题,因为实际类型可以通过上下文推断出来,且操作符已经为合适的转换进行了重载,例如:

[code lang=”kotlin”]val l = 1L + 3 // Long + Int => Long[/code]

【注】上面的代码中,等号右边 1LLong 型,3Int 型。Long+ 操作符有针对 Int重载

[code lang=”kotlin”]operator fun plus(other: Int): Long (source)[/code]

Long + Int 的结果是 Long。故等号左边 val l 的类型是 Long。操作符重载的更多内容见操作符重载

Operations

  Kotlin 支持数值类型间的一系列标准运算,这些运算都声明为了对应类的方法(编译器会把调用优化为对应的指令),见 Operator Overloading

  对于位运算,并没有专用的操作符,但可以用中缀的形式调用命名函数,如:

[code lang=”kotlin”]val x = (1 shl 2) and 0x000FF000[/code]

  完整的位运算操作符列举如下(仅可用于 IntLong):

  • shl(bits) – 带符号左移(Java 中的 <<
  • shr(bits) – 带符号右移(Java 中的 >>
  • ushr(bits) – 无符号左移(Java 中的 >>>
  • and(bits) – 按位与
  • or(bits) – 按位或
  • xor(bits) – 按位异或
  • inv() – 按位反转

Characters

  Char 类型用于表示字符,不能把它直接当成数字使用:

[code lang=”kotlin”]fun check(c: Char) {
if (c == 1) { // ERROR: incompatible types
// …
}
}[/code]

  字符字面值使用单引号:’1’。可以使用反斜杠来转义特殊字符,支持的转义序列有:\t\b\n\r\'\"\\\$。如果要编码其他字符,可以使用 Unicode 转义序列的语法:'\uFF00'

  我们可以显式地把字符转换为 Int 型数值:

[code lang=”kotlin”]fun decimalDigitValue(c: Char): Int {
if (c !in ‘0’..’9′)
throw IllegalArgumentException(“Out of range”)
return c.toInt() – ‘0’.toInt() // Explicit conversions to numbers
}[/code]

  在引入空引用时,Char 也会被装箱,就像数值类型一样。Char 装箱后也不保持一致性。

Booleans

  Boolean 表示布尔类型,有 true 和 false 两个值。Boolean 也会在引入空引用时装箱,内置的操作有:

  • ||:短路或
  • &&:短路与
  • !:取反

Arrays

  Array 表示数组类型,具有 getset 方法(通过操作符重载为 [])和 size 属性,以及其他一些常用成员函数:

[code lang=”kotlin”]class Array private constructor() {
val size: Int
operator fun get(index: Int): T
operator fun set(index: Int, value: T): Unit

operator fun iterator(): Iterator
// …
}[/code]

  可以使用库函数 arrayOf() 并传递初始值来创建数组,如 arrayOf(1, 2, 3) 会创建数组 [1, 2, 3]。此外,使用库函数 arrayOfNulls() 可以创建指定大小、以 null 填充的数组。

  还可以使用工厂函数创建数组,需要提供数组容量和一个计算数组各个位置上的值的函数:

[code lang=”kotlin”]// Creates an Array with values [“0”, “1”, “4”, “9”, “16”]
val asc = Array(5, { i -> (i * i).toString() })[/code]

  就像上面提到的,[] 操作表示调用 get()set() 成员函数。

  注意:Kotlin 中的数组是不变量,这一点和 Java 不同。这意味着 Kotlin 不允许把 Array<String> 赋给 Array<Any>,因为这样可能会带来运行时错误(但可以使用 Array<out Any>,见 类型投射)。

  Kotlin 提供了一系列专用的类来表示基本类型数组,以避免装箱带来的开销,如 ByteArrayShortArrayIntArray 等,这些数组并不继承自 Array 类,但提供了和 Array 相同的方法和属性。它们也有对应的工厂方法,如:

[code lang=”kotlin”]val x: IntArray = intArrayOf(1, 2, 3)
x[0] = x[1] + x[2][/code]

Strings

  String 表示字符串类型。,String 是不可变的,其中的各个字符可以使用索引操作来访问,如 s[i]。可以使用 for 循环遍历 String:

[code lang=”kotlin”]for (c in str) {
println(c)
}[/code]

String Literals

  Kotlin 有两种字符串字面值表示方法,带转义的字符串(Escaped String)可以包含转义字符,原始字符串(Raw String)可以包含换行(Newline)和任意文本。带转义的字符串(Escaped String)和 Java 的字符串非常类似:

[code lang=”kotlin”]val s = “Hello, world!\n”[/code]

  原始字符串使用三个双引号包围,不需要转义,可以包含换行和任意字符,如:

[code lang=”kotlin”]val text = “””
for (c in “foo”)
print(c)
“””[/code]

可以使用 trimMargin() 函数移除开头的空格:

[code lang=”kotlin”]val text = “””
|Tell me and I forget.
|Teach me and I remember.
|Involve me and I learn.
|(Benjamin Franklin)
“””.trimMargin()[/code]

这里的 | 是默认的边界标识符,也可以使用其他字符,只需以参数的形式传递给 trimMargin() 即可,如 trimMargin(">")

String Templates

  字符串可以包含模板表达式(Template Expression),表达式的值会被计算并拼接在字符串中。模板表达式以 $ 符号开头,可以包含简单的名称:

[code lang=”kotlin”]val i = 10
val s = “i = $i” // evaluates to “i = 10″[/code]

或者包围在大括号里的任意表达式:

[code lang=”kotlin”]val s = “abc”
val str = “$s.length is ${s.length}” // evaluates to “abc.length is 3″[/code]

  原始字符串和带转义的字符串都支持模板。如果要在原始字符串中加入 $ 字符(原始字符串不支持反斜杠转义),需要使用如下的语法:

[code lang=”kotlin”]val price = “””
${‘$’}9.99
“””[/code]