Kotlin Reference: Basic Types
本系列翻译自 Kotlin 官方文档,并对一些疑难点添加了备注,以【注】
标记。
Kotlin 中一切皆对象,也就是说,我们可以调用任意变量的成员函数和属性。虽然一些内置类型的实现经过了优化,但对用户来说,它们仍表现为普通的类,本节就描述了这些类型:数字、字符、布尔和数组。
Contents
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.5
,123.5e10
- 单精度浮点以
f
或F
结尾: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]
【注】上面的代码中,等号右边 1L
是 Long
型,3
是 Int
型。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]
完整的位运算操作符列举如下(仅可用于 Int
和 Long
):
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
表示数组类型,具有 get
和 set
方法(通过操作符重载为 []
)和 size
属性,以及其他一些常用成员函数:
[code lang=”kotlin”]class Array
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
val asc = Array(5, { i -> (i * i).toString() })[/code]
就像上面提到的,[]
操作表示调用 get()
和 set()
成员函数。
注意:Kotlin 中的数组是不变量,这一点和 Java 不同。这意味着 Kotlin 不允许把 Array<String>
赋给 Array<Any>
,因为这样可能会带来运行时错误(但可以使用 Array<out Any>
,见 类型投射)。
Kotlin 提供了一系列专用的类来表示基本类型数组,以避免装箱带来的开销,如 ByteArray
、ShortArray
、IntArray
等,这些数组并不继承自 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]