4.4 基本类型(Primitive Types)

本节我们来探讨学习:Kotlin的基础类型:数字、字符、布尔和数组等。

我们知道Java的类型分成两种:一种是基本类型,一种是引用类型。它们的本质区别是:

基本类型是在堆栈处分配空间存“值”,而引用类型是在堆里面分配空间存“值”。

Java的基本类型有: byte、int、short、long、float、double、char、boolean,这些类都有对应的装箱类(引用类型)。

另外,void也可以算是一种特殊的基本类型,它也有一个装箱类Void(跟我们后文讲到的Unit、Nothing相关)。因为,Void是不能new出来的,也就是不能在堆里面分配空间存对应的值。所以,Void是一开始在堆栈处分配好空间。所以,将Void归成基本类型。

在Kotlin中,一切皆是对象。所有类型都是引用类型。没有类似Java中的基本类型。但是,可以把Kotlin中对应的这几种基本数据类型,理解为Java的基本类型的装箱类。

Integer.java

  1. public final class Integer extends Number implements Comparable<Integer> {
  2. /**
  3. * A constant holding the minimum value an {@code int} can
  4. * have, -2<sup>31</sup>.
  5. */
  6. @Native public static final int MIN_VALUE = 0x80000000;
  7. /**
  8. * A constant holding the maximum value an {@code int} can
  9. * have, 2<sup>31</sup>-1.
  10. */
  11. @Native public static final int MAX_VALUE = 0x7fffffff;
  12. /**
  13. * The {@code Class} instance representing the primitive type
  14. * {@code int}.
  15. *
  16. * @since JDK1.1
  17. */
  18. @SuppressWarnings("unchecked")
  19. public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
  20. ...
  21. }

Kotlin中的Int类型:

  1. public class Int private constructor() : Number(), Comparable<Int> {
  2. companion object {
  3. /**
  4. * A constant holding the minimum value an instance of Int can have.
  5. */
  6. public const val MIN_VALUE: Int = -2147483648
  7. /**
  8. * A constant holding the maximum value an instance of Int can have.
  9. */
  10. public const val MAX_VALUE: Int = 2147483647
  11. }
  12. ...
  13. }

我们通过Java的Integer封装类,跟Kotlin的Int类的定义可以看出两者的思想上的同源性。

Kotlin的基本类型的类图结构如下图所示

Kotlin极简教程

4.4.1 数字(Number)类型

Kotlin 提供了如下的内置类型来表示数字(与 Java 很相近):

类型 宽度(Bit)
Double 64
Float 32
Long 64
Int 32
Short 16
Byte 8

从上面的Kotlin的基本类型的类的结构图,我们可以看出这些内置的数据类型,都继承了NumberComparable类。例如,Byte类型的声明:

  1. public class Byte private constructor() : Number(), Comparable<Byte> {
  2. ...
  3. }

Kotlin 的数字类型跟 Java 基本相同。有一点不同的是,Kotlin 对于数字没有隐式拓宽转换(如 Java 中 int 可以隐式转换为long)。

注意在 Kotlin 中字符Char不是数字。这些基本数据类型,会在运行时自动优化为Java的double、float、long、int、short、byte。

字面常量值(literal constant values)

数值常量字面值有以下几种:

  • 十进制: 123
  • Long 类型用大写 L 标记: 123L
  • 十六进制: 0x0F
  • 二进制: 0b00001011

代码示例:

  1. >>> 123
  2. 123
  3. >>> 123::class
  4. class kotlin.Int
  5. >>> 123::class.java
  6. int
  7. >>> 123L
  8. 123
  9. >>> 123L::class
  10. class kotlin.Long
  11. >>> 123L::class.java
  12. long
  13. >>> val b:Byte=128
  14. error: the integer literal does not conform to the expected type Byte
  15. val b:Byte=128
  16. ^
  17. >>> val b:Byte=127
  18. >>> b::class
  19. class kotlin.Byte
  20. >>> b::class.java
  21. byte
  22. >>> 0x0f
  23. 15
  24. >>> 0x0F
  25. 15
  26. >>> 0b1000
  27. 8

同样的,当我们赋值超过变量的类型的取值范围时,编译器会直接抛错。

注意: 不支持八进制

Kotlin 同样支持浮点数的常规表示方法:

  • 默认 double:123.5123.5e10
  • Float 用 f 或者 F 标记: 123.5f

代码示例:

  1. >>> 1234.5
  2. 1234.5
  3. >>> 1234.5::class
  4. class kotlin.Double
  5. >>> 1234.5::class.java
  6. double
  7. >>> 12.3e10
  8. 1.23E11
  9. >>> 12.3e10::class
  10. class kotlin.Double
  11. >>> 456.7f
  12. 456.7
  13. >>> 456.7f::class
  14. class kotlin.Float
  15. >>> 456.7f::class.java
  16. float

我们也可以使用数字字面值中的下划线(自 1.1 起),使数字常量更易读:

  1. >>> 1_000_000
  2. 1000000
  3. >>> 1234_5678_9012_3456L
  4. 1234567890123456
  5. >>> 0xFF_EC_DE_5E
  6. 4293713502
  7. >>> 0b11010010_01101001_10010100_10010010
  8. 3530134674

在 Java 平台数字是物理存储为 JVM 的原生类型,除非我们需要一个可空的引用(如 Int?)或泛型。
后者情况下会把数字装箱。

显式转换

由于不同的表示方式,值范围较小类型并不是较大类型的子类型,是不能隐式转换的。

代码示例:

  1. >>> val a: Int? = 1
  2. >>> val b: Long? = a
  3. error: type mismatch: inferred type is Int? but Long? was expected
  4. val b: Long? = a
  5. ^
  6. >>> val b: Byte = 1
  7. >>> val i: Int = b
  8. error: type mismatch: inferred type is Byte but Int was expected
  9. val i: Int = b
  10. ^

这意味着在不进行显式转换的情况下我们不能把 Int 型值赋给一个 Long 变量。也不能把 Byte 型值赋给一个 Int 变量。

我们可以显式转换来拓宽数字

  1. >>> val i: Int = b.toInt() // OK: 显式拓宽

每个数字类型都继承Number抽象类,其中定义了如下的转换函数:

  1. toDouble(): Double
  2. toFloat(): Float
  3. toLong(): Long
  4. toInt(): Int
  5. toChar(): Char
  6. toShort(): Short
  7. toByte(): Byte

所以,在数字之间的转换,我们直接调用上面的这些转换函数即可。

运算符+重载

缺乏隐式类型转换并不显著,因为类型会从上下文推断出来,而算术运算会有重载做适当转换,例如:

  1. val l = 1L + 3 // Long + Int => Long

这个是通过运算符+重载实现的。我们可以在Long类的源代码中看到这个plus 运算符函数的定义:

  1. public operator fun plus(other: Byte): Long
  2. public operator fun plus(other: Short): Long
  3. public operator fun plus(other: Int): Long
  4. public operator fun plus(other: Long): Long
  5. public operator fun plus(other: Float): Float
  6. public operator fun plus(other: Double): Double

也就是说, 编译器会把1L + 3 翻译成 1L.plus(3),然后这个传入的参数类型必须是Byte、Short、Int、Long、Float、Double中的一种。例如,我们传入一个字符Char参数,编译器就会直接抛错:

  1. >>> 'a'
  2. a
  3. >>> 'a'::class
  4. class kotlin.Char
  5. >>> 'a'::class.java
  6. char
  7. >>> 1L+'a'
  8. error: none of the following functions can be called with the arguments supplied:
  9. public final operator fun plus(other: Byte): Long defined in kotlin.Long
  10. public final operator fun plus(other: Double): Double defined in kotlin.Long
  11. public final operator fun plus(other: Float): Float defined in kotlin.Long
  12. public final operator fun plus(other: Int): Long defined in kotlin.Long
  13. public final operator fun plus(other: Long): Long defined in kotlin.Long
  14. public final operator fun plus(other: Short): Long defined in kotlin.Long
  15. 1L+'a'
  16. ^

运算

Kotlin支持数字运算的标准集,运算被定义为相应的类成员(但编译器会将函数调用优化为相应的指令)。

对于位运算,没有特殊字符来表示,而只可用中缀方式调用命名函数(infix fun),例如:

  1. val x = (1 shl 2) and 0x000FF000

这是完整的位运算列表(只用于 IntLong):

  • shl(bits) – 有符号左移 (Java 的 <<)
  • shr(bits) – 有符号右移 (Java 的 >>)
  • ushr(bits) – 无符号右移 (Java 的 >>>)
  • and(bits) – 位与
  • or(bits) – 位或
  • xor(bits) – 位异或
  • inv() – 位非

    4.4.2 Char: 字符(Character)类型与转义符(Escape character)

字符用 Char 类型表示。它们不能直接当作数字

  1. fun check(c: Char) {
  2. if (c == 1) { // 错误:类型不兼容
  3. // ……
  4. }
  5. }

字符字面值用 单引号 括起来: '1'
特殊字符可以用反斜杠转义。

Kotlin支持如下转义字符:

  1. \t
  2. \b
  3. \n
  4. \r
  5. \`
  6. \"
  7. \\
  8. \$

编码其他字符要用 Unicode 转义序列语法,例如:'\uFF00'

Char类的函数接口定义如下:

  1. public class Char private constructor() : Comparable<Char> {
  2. /**
  3. * Compares this value with the specified value for order.
  4. * Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
  5. * or a positive number if it's greater than other.
  6. */
  7. public override fun compareTo(other: Char): Int
  8. /** Adds the other Int value to this value resulting a Char. */
  9. public operator fun plus(other: Int): Char
  10. /** Subtracts the other Char value from this value resulting an Int. */
  11. public operator fun minus(other: Char): Int
  12. /** Subtracts the other Int value from this value resulting a Char. */
  13. public operator fun minus(other: Int): Char
  14. /** Increments this value. */
  15. public operator fun inc(): Char
  16. /** Decrements this value. */
  17. public operator fun dec(): Char
  18. /** Creates a range from this value to the specified [other] value. */
  19. public operator fun rangeTo(other: Char): CharRange
  20. /** Returns the value of this character as a `Byte`. */
  21. public fun toByte(): Byte
  22. /** Returns the value of this character as a `Char`. */
  23. public fun toChar(): Char
  24. /** Returns the value of this character as a `Short`. */
  25. public fun toShort(): Short
  26. /** Returns the value of this character as a `Int`. */
  27. public fun toInt(): Int
  28. /** Returns the value of this character as a `Long`. */
  29. public fun toLong(): Long
  30. /** Returns the value of this character as a `Float`. */
  31. public fun toFloat(): Float
  32. /** Returns the value of this character as a `Double`. */
  33. public fun toDouble(): Double
  34. }

我们来用代码示例这些函数的使用:

如果两个字符相等:

  1. >>> 'a'.compareTo('a')
  2. 0

如果两个字符不相等:

  1. >>> 'a'.compareTo('b')
  2. -1
  3. >>> 'a'.compareTo('c')
  4. -1
  5. >>> 'b'.compareTo('a')
  6. 1
  7. >>> 'c'.compareTo('a')
  8. 1

Char字符只重载了加上Int类型的数字的+运算符:

  1. >>> 'a'+1
  2. b
  3. >>> 'a'+1L
  4. error: the integer literal does not conform to the expected type Int
  5. 'a'+1L

所以,当我们把一个Char类型值和不是Int类型的值相加,就报错了。

相减:

  1. >>> 'a'-1
  2. `
  3. >>> 'c'-'a'
  4. 2

自增计算:

  1. >>> var a='a'
  2. >>> val b=a++
  3. >>> a
  4. b
  5. >>> b
  6. a
  7. >>> val c=++a
  8. >>> c
  9. c

我们不能在字符的字面量上直接使用++:

  1. >>> 'a'++
  2. error: variable expected
  3. 'a'++
  4. ^
  5. >>> ++'a'
  6. error: variable expected
  7. ++'a'
  8. ^

范围

  1. >>> 'a'.rangeTo('z')
  2. a..z
  3. >>> for(c in 'a'..'z') {print(c)}
  4. abcdefghijklmnopqrstuvwxyz

Char的显式类型转换函数如下:

  1. /** Returns the value of this character as a `Byte`. */
  2. public fun toByte(): Byte
  3. /** Returns the value of this character as a `Char`. */
  4. public fun toChar(): Char
  5. /** Returns the value of this character as a `Short`. */
  6. public fun toShort(): Short
  7. /** Returns the value of this character as a `Int`. */
  8. public fun toInt(): Int
  9. /** Returns the value of this character as a `Long`. */
  10. public fun toLong(): Long
  11. /** Returns the value of this character as a `Float`. */
  12. public fun toFloat(): Float
  13. /** Returns the value of this character as a `Double`. */
  14. public fun toDouble(): Double

例如,我们显式把字符转换为 Int 数字:

  1. fun decimalDigitValue(c: Char): Int {
  2. if (c !in '0'..'9')
  3. throw IllegalArgumentException("Out of range")
  4. return c.toInt() - '0'.toInt() // 显式转换为数字
  5. }

测试代码:

  1. >>> decimalDigitValue('a')
  2. java.lang.IllegalArgumentException: Out of range
  3. at Line24.decimalDigitValue(Unknown Source)
  4. >>> decimalDigitValue('1')
  5. 1

4.4.3 Boolean: 布尔类型

Kotlin的布尔类型用 Boolean 类来表示,它有两个值:truefalse

  1. >>> true::class
  2. class kotlin.Boolean
  3. >>> true::class.java
  4. boolean

对应Java中的boolean类型。

其源码定义如下:

  1. package kotlin
  2. /**
  3. * Represents a value which is either `true` or `false`. On the JVM, non-nullable values of this type are
  4. * represented as values of the primitive type `boolean`.
  5. */
  6. public class Boolean private constructor() : Comparable<Boolean> {
  7. /**
  8. * Returns the inverse of this boolean.
  9. */
  10. public operator fun not(): Boolean
  11. /**
  12. * Performs a logical `and` operation between this Boolean and the [other] one.
  13. */
  14. public infix fun and(other: Boolean): Boolean
  15. /**
  16. * Performs a logical `or` operation between this Boolean and the [other] one.
  17. */
  18. public infix fun or(other: Boolean): Boolean
  19. /**
  20. * Performs a logical `xor` operation between this Boolean and the [other] one.
  21. */
  22. public infix fun xor(other: Boolean): Boolean
  23. public override fun compareTo(other: Boolean): Int
  24. }

从上面我们可以看出,Boolean类的内置的布尔运算有:

  • ! 逻辑非 not()

  • && 短路逻辑与 and()

  • || 短路逻辑或or()

  • xor 异或(相同false,不同true)

另外,Boolean还继承实现了ComparablecompareTo()函数。

代码示例:

  1. >>> !true
  2. false
  3. >>> true.not()
  4. false
  5. >>> true && true
  6. true
  7. >>> true.and(false)
  8. false
  9. >>> true || false
  10. true
  11. >>> false.or(false)
  12. false
  13. >>> true xor true
  14. false
  15. >>> true xor false
  16. true
  17. >>> false xor false
  18. false
  19. >>> true > false
  20. true
  21. >>> true < false
  22. false
  23. >>> true.compareTo(false)
  24. 1
  25. >>> true.compareTo(false)
  26. 1
  27. >>> true.compareTo(true)
  28. 0
  29. >>> false.compareTo(true)
  30. -1

4.4.4 String: 字符串类型

Kotlin的字符串用 String 类型表示。对应Java中的java.lang.String。字符串是不可变的。

  1. >>> "abc"::class
  2. class kotlin.String
  3. >>> "abc"::class.java
  4. class java.lang.String

另外,在Kotlin中,String同样是final不可继承的。

代码示例:

  1. >>> class MyString:String
  2. error: this type is final, so it cannot be inherited from
  3. class MyString:String
  4. ^

索引运算符 s[i]

字符串的元素——字符可以使用索引运算符 s[i]来访问。

  1. >>> val s="abc"
  2. >>> s
  3. abc
  4. >>> s[0]
  5. a

当我们下标越界时,会抛越界错误:

  1. >>> s[-1]
  2. java.lang.StringIndexOutOfBoundsException: String index out of range: -1
  3. at java.lang.String.charAt(String.java:646)
  4. >>> s[3]
  5. java.lang.StringIndexOutOfBoundsException: String index out of range: 3
  6. at java.lang.String.charAt(String.java:646)

从出错信息,我们可以看出,索引运算符 s[i]会被翻译成java.lang.String.charAt(), 背后调用的是Java的String类。其调用的方法是:

  1. public char charAt(int index) {
  2. if ((index < 0) || (index >= value.length)) {
  3. throw new StringIndexOutOfBoundsException(index);
  4. }
  5. return value[index];
  6. }

for 循环迭代字符串

我们可以用 for 循环迭代字符串:

  1. >>> for(c in "abc") { println(c) }
  2. a
  3. b
  4. c

关于字符串String类的完整的操作方法,我们可以看下源码:

  1. public class String : Comparable<String>, CharSequence {
  2. companion object {}
  3. /**
  4. * Returns a string obtained by concatenating this string with the string representation of the given [other] object.
  5. */
  6. public operator fun plus(other: Any?): String
  7. public override val length: Int
  8. public override fun get(index: Int): Char
  9. public override fun subSequence(startIndex: Int, endIndex: Int): CharSequence
  10. public override fun compareTo(other: String): Int
  11. }

类似的,字符串有一个length属性:

  1. >>> "abc".length
  2. 3

重载+操作符

字符串类重载了+操作符,作用对象可以是任何对象,包括空引用:

  1. >>> "abc".plus(true)
  2. abctrue
  3. >>> "abc"+false
  4. abcfalse
  5. >>> "abc"+1
  6. abc1
  7. >>> "abc"+1.20
  8. abc1.2
  9. >>> "abc"+100L
  10. abc100
  11. >>> "abc"+"cdef"
  12. abccdef
  13. >>> "abc"+null
  14. abcnull
  15. >>> "abc"+'z'
  16. abcz
  17. >>> "abc"+arrayOf(1,2,3,4,5)
  18. abc[Ljava.lang.Integer;@3d6f0054

截取字符串的子串:

  1. >>> "abc".subSequence(0,1)
  2. a
  3. >>> "abc".subSequence(0,2)
  4. ab
  5. >>> "abc".subSequence(0,3)
  6. abc
  7. >>> "abc".subSequence(0,4)
  8. java.lang.StringIndexOutOfBoundsException: String index out of range: 4
  9. at java.lang.String.substring(String.java:1951)
  10. at java.lang.String.subSequence(String.java:1991)

字符串字面值

字符串的字面值,可以包含原生字符串可以包含换行和任意文本,也可以是带有转义字符(Escape Charactor)的转义字符串。

  1. >>> val s = "Hello,World!\n\n\n"
  2. >>> s
  3. Hello,World!
  4. >>>

转义采用传统的反斜杠方式。

原生字符串使用三个引号(""")分界符括起来,内部没有转义并且可以包含换行和任何其他字符:

  1. >>> val text = """
  2. ... for (c in "abc")
  3. ... print(c)
  4. ... """
  5. >>> text
  6. for (c in "foo")
  7. print(c)
  8. >>>

另外,在package kotlin.text下面的Indent.kt代码中,Kotlin还定义了String类的扩展函数:

  1. fun String.trimMargin(marginPrefix: String = "|"): String
  2. fun String.trimIndent(): String

我们可以使用trimMargin()trimIndent() 裁剪函数来去除前导空格。可以看出,trimMargin()函数默认使用 "|" 来作为边界字符:

  1. >>> val text = """
  2. ... |理论是你知道是这样,但它却不好用。
  3. ... |实践是它很好用,但你不知道是为什么。
  4. ... |程序员将理论和实践结合到一起:
  5. ... |既不好用,也不知道是为什么。
  6. ... """
  7. >>> text.trimMargin()
  8. 理论是你知道是这样,但它却不好用。
  9. 实践是它很好用,但你不知道是为什么。
  10. 程序员将理论和实践结合到一起:
  11. 既不好用,也不知道是为什么。

默认 | 用作边界前缀,但你可以选择其他字符并作为参数传入,比如 trimMargin(">")

trimIndent()函数,则是把字符串行的左边空白对齐切割:

  1. >>> val text="""
  2. ... Hello
  3. ... World!
  4. ... """
  5. >>> text.trimIndent()
  6. Hello
  7. World!
  8. >>> val text="""
  9. ... Hello,
  10. ... World!
  11. ... """
  12. >>> text.trimIndent()
  13. Hello,
  14. World!

字符串模板

字符串可以包含模板表达式,即一些小段代码,会求值并把结果合并到字符串中。
模板表达式以美元符($)开头,由一个简单的名字构成:

  1. >>> val h=100
  2. >>> val str = "A hundred is $h"
  3. >>> str
  4. A hundred is 100

或者用花括号扩起来的任意表达式:

  1. >>> val s = "abc"
  2. >>> val str = "$s.length is ${s.length}"
  3. >>> str
  4. abc.length is 3

原生字符串和转义字符串内部都支持模板。

  1. >>> val price=9.9
  2. >>> val str="""Price is $$price"""
  3. >>> str
  4. Price is $9.9
  5. >>> val str="Price is $$price"
  6. >>> str
  7. Price is $9.9
  8. >>> val quantity=100
  9. >>> val str="Quantity is $quantity"
  10. >>> str
  11. Quantity is 100
  12. >>> val str="""Quantity is $quantity"""
  13. >>> str
  14. Quantity is 100

4.4.5 Array: 数组类型

数组在 Kotlin 中使用 Array 类来表示,它定义了 getset 函数(映射到重载运算符 [])和 size 属性,以及一个用于变量数组的iterator()函数:

  1. class Array<T> private constructor() {
  2. val size: Int
  3. operator fun get(index: Int): T
  4. operator fun set(index: Int, value: T): Unit
  5. operator fun iterator(): Iterator<T>
  6. // ……
  7. }

我们可以使用函数 arrayOf() 来创建一个数组并传递元素值给它。这个函数签名如下:

  1. public inline fun <reified @PureReifiable T> arrayOf(vararg elements: T): Array<T>

其中,vararg表示是一个参数个数是一个变量。

例如, arrayOf(1, 2, 3) 创建了 array [1, 2, 3] :

  1. >>> arrayOf(1,2,3)
  2. [Ljava.lang.Integer;@4a37191a
  3. >>> arrayOf(1,2,3)::class
  4. class kotlin.Array
  5. >>> arrayOf(1,2,3)::class.java
  6. class [Ljava.lang.Integer;

另外,Kotlin还允许不同类型元素放到一个数组中,例如:

  1. >>> val arr = arrayOf(1,"2",true)
  2. >>> arr
  3. [Ljava.lang.Object;@61af1510
  4. >>> arr.forEach{ println(it) }
  5. 1
  6. 2
  7. true
  8. >>> arr.forEach{ println(it::class) }
  9. class kotlin.Int
  10. class kotlin.String
  11. class kotlin.Boolean

Kotlin自动把这个数组元素的类型升级为java.lang.Object, 同时,由于Kotlin拥有的类型推断的功能,我们仍然可以看到每个数组元素对应的各自的类型。

函数 arrayOfNulls() 可以用于创建一个指定大小、元素都为空的数组。这个特殊的空数组在创建的时候,我们需要指定元素的类型。如果不指定,直接按照下面这样写,会报错:

  1. >>> arrayOfNulls(10)
  2. error: type inference failed: Not enough information to infer parameter T in fun <reified T> arrayOfNulls(size: Int): Array<T?>
  3. Please specify it explicitly.
  4. arrayOfNulls(10)
  5. ^

也就是说,我们要指定

  1. >>> arrayOfNulls<Int>(10)
  2. [Ljava.lang.Integer;@77c10a5f
  3. >>> arrayOfNulls<Int>(10).forEach{println(it)}
  4. null
  5. null
  6. null
  7. null
  8. null
  9. null
  10. null
  11. null
  12. null
  13. null

数组Array类,还提供了一个构造函数:

  1. public inline constructor(size: Int, init: (Int) -> T)

第1个参数是数组大小,第2个参数是一个初始化函数类型的参数(关于函数类型,我们将在后面章节介绍)。

代码示例:

  1. >>> val square = Array(10, { i -> (i*i)})
  2. >>> square
  3. [Ljava.lang.Integer;@6f9e08d4
  4. >>> square.forEach{ println(it) }
  5. 0
  6. 1
  7. 4
  8. 9
  9. 16
  10. 25
  11. 36
  12. 49
  13. 64
  14. 81

如上所述,[] 运算符代表调用成员函数 get()set()
代码示例:

  1. >>> square[3]
  2. 9
  3. >>> square[3]=1000
  4. >>> square.forEach{ println(it) }
  5. 0
  6. 1
  7. 4
  8. 1000
  9. 16
  10. 25
  11. 36
  12. 49
  13. 64
  14. 81

与 Java 不同的是,Kotlin 中数组不是型变的(invariant)。 Kotlin中,我们不能把 Array<String> 赋值给 Array<Any>。这地方Kotlin类型检查的限制强于Java的数组类型。

代码示例:

  1. >>> val arrstr = arrayOf<String>("1","2","3")
  2. >>> arrstr
  3. [Ljava.lang.String;@39374689
  4. >>> var arrany = arrayOf<Any>(Any(),Any(),Any())
  5. >>> arrany
  6. [Ljava.lang.Object;@156324b
  7. >>> arrany = arrstr
  8. error: type mismatch: inferred type is Array<String> but Array<Any> was expected
  9. arrany = arrstr
  10. ^

原生数组类型

Kotlin 也有无装箱开销的专门的类来表示原生类型数组。这些原生数组类如下:

  • BooleanArray
  • ByteArray
  • CharArray
  • ShortArray
  • IntArray
  • LongArray
  • FloatArray
  • DoubleArray
  • BooleanArray

这些类和 Array 并没有继承关系,但它们有同样的函数和属性集。它们也都有相应的工厂方法:

  1. /**
  2. * Returns an array containing the specified [Double] numbers.
  3. */
  4. public fun doubleArrayOf(vararg elements: Double): DoubleArray
  5. /**
  6. * Returns an array containing the specified [Float] numbers.
  7. */
  8. public fun floatArrayOf(vararg elements: Float): FloatArray
  9. /**
  10. * Returns an array containing the specified [Long] numbers.
  11. */
  12. public fun longArrayOf(vararg elements: Long): LongArray
  13. /**
  14. * Returns an array containing the specified [Int] numbers.
  15. */
  16. public fun intArrayOf(vararg elements: Int): IntArray
  17. /**
  18. * Returns an array containing the specified characters.
  19. */
  20. public fun charArrayOf(vararg elements: Char): CharArray
  21. /**
  22. * Returns an array containing the specified [Short] numbers.
  23. */
  24. public fun shortArrayOf(vararg elements: Short): ShortArray
  25. /**
  26. * Returns an array containing the specified [Byte] numbers.
  27. */
  28. public fun byteArrayOf(vararg elements: Byte): ByteArray
  29. /**
  30. * Returns an array containing the specified boolean values.
  31. */
  32. public fun booleanArrayOf(vararg elements: Boolean): BooleanArray

代码示例:

  1. >>> val x: IntArray = intArrayOf(1, 2, 3)
  2. >>> x[0]
  3. 1