先来谈谈数组,也可参考 Kotlin 快速入门#数组
数组在 Kotlin 中使用 Array
类来表示,它定义了 get
和 set
函数(按照运算符重载约定这会转变为 []
)和 size
属性,以及一些其他有用的成员函数:
class Array<T> private constructor() {
val size: Int
operator fun get(index: Int): T
operator fun set(index: Int, value: T): Unit
operator fun iterator(): Iterator<T>
// ……
}
Library.kt
中 arrayOf()
arrayOfNulls
函数以及Array
构造函数能创建数组:
val args: Array<Int> = arrayOf(1, 2, 3)
val arrayOfNulls = arrayOfNulls<Int>(10) //空数组
val initArray = Array(5, { i -> (i * i).toString() }) //构造函数init
println(arrayOfNulls.size)
NOTE: 与 Java 不同的是,Kotlin 中数组是不型变的(invariant)。这意味着 Kotlin 不让我们把 Array
赋值给 Array
,以防止可能的运行时失败(但是你可以使用 Array
, 参见类型投影)。
之前所说的在泛型情况下Kotlin 会把数字和字符自动装箱成相应包装类, Arrays.kt
中有以下
ByteArray
CharArray
ShortArray
IntArray
LongArray
FloatArray
DoubleArray
BooleanArray
无装箱开销的专门的类来表示原生类型数组, 和 Array
并没有继承关系,但是它们有同样的方法属性集。它们也都有相应的工厂方法。
val x: IntArray = intArrayOf(1, 2, 3)
x[0] = x[1] + x[2]
数组迭代通过 iterator()
函数返回 Iterator
对象进行迭代:
val iterator = args.iterator()
while (iterator.hasNext()) {
print("" + iterator.next())
}
println()
//forEach
args.iterator().forEach { print(it) }
println()
//for-
for (it in initArray/*.iterator()*/) {
print(it)
}
println()
//下标索引
args.forEachIndexed { index, i -> println("$index = $i") }
NOTE: forEach
forEachIndexed
这些是Array 的扩展函数, 背后实现也是 [for 循环 ](#For 循环)
arrayOf(1,2)//vs Java: new Integer[]{1, 2};
intArrayOf(1, 2) //vs Java new int[]{1, 2};
val newArray = intArrayOf(1, 2, *(intArrayOf(3, 4)))
/*vs Java
IntSpreadBuilder var4 = new IntSpreadBuilder(3);
var4.add(1);
var4.add(2);
var4.addSpread(new int[]{3, 4});
int[] newArray = var4.toArray();*/
如上面 的 intArrayOf(vararg elements: Int)
的函数还可以接收数组对象地址,从而新建一个原数据顺序的数组。由字节码分析可以知道,当接收数组对象地址时,arrayOf 复杂了点,主要是PrimitiveSpreadBuilders.kt 这个文件,它下面声明了 PrimitiveSpreadBuilder
对象,以及基本类型的对应的子对象 ByteSpreadBuilder、CharSpreadBuilder、DoubleSpreadBuilder、FloatSpreadBuilder、IntSpreadBuilder、LongSpreadBuilder、ShortSpreadBuilder、BooleanSpreadBuilder
看完源码后,直到关注的只有3个点
add(value: Int)
实现的,并保存到values
相关类型数组集合里面addSpread(spreadArgument: T)
实现的,并保存到 spreads
数组集合里面toArray(values: T, result: T): T
该函数在基类里完成values、spreads数据拷贝到result 数组中public abstract class PrimitiveSpreadBuilder(private val size: Int) {
abstract protected fun T.getSize(): Int
//当前 elements pos
protected var position: Int = 0
//用于存放数组的数组集合,且大小同elements size,且position同elements 中一致
@Suppress("UNCHECKED_CAST")
private val spreads: Array = arrayOfNulls(size) as Array
//添加数组到相应位置
public fun addSpread(spreadArgument: T) {
spreads[position++] = spreadArgument
}
//计算新数组的size
protected fun size(): Int {
var totalLength = 0
for (i in 0..size - 1) {
totalLength += spreads[i]?.getSize() ?: 1
}
return totalLength
}
//复制单个元素和单个数组到新数组result中
protected fun toArray(values: T, result: T): T {
//新数组result待插入位置
var dstIndex = 0
//copy values元素到result时,values的开始copy位置
var copyValuesFrom = 0
//for each elements
for (i in 0..size - 1) {
val spreadArgument = spreads[i]
if (spreadArgument != null) {
//不为null 的spreadArgument肯定是个数组对象
if (copyValuesFrom < i) {
//开始copy这个数组前面的元素(1个或多个)
System.arraycopy(values, copyValuesFrom, result, dstIndex, i - copyValuesFrom)
//copy 后
dstIndex += i - copyValuesFrom
}
val spreadSize = spreadArgument.getSize()
//copy 该数组所有元素到result数组中
System.arraycopy(spreadArgument, 0, result, dstIndex, spreadSize)
dstIndex += spreadSize
//copy 后
copyValuesFrom = i + 1
}
}
//elements 中没发现数组对象,直接copy values元素到result
if (copyValuesFrom < size) {
System.arraycopy(values, copyValuesFrom, result, dstIndex, size - copyValuesFrom)
}
return result
}
}
//size 是intArrayOf() elements 的size
public class IntSpreadBuilder(size: Int) : PrimitiveSpreadBuilder(size) {
//用于存放单个元素的数组集合,且大小同elements size,且position同elements 中一致
private val values: IntArray = IntArray(size)
//扩展函数,返回数组的长度
override fun IntArray.getSize(): Int = this.size
//添加元素到相应位置
public fun add(value: Int) {
values[position++] = value
}
//调用父类toArray()
public fun toArray(): IntArray = toArray(values, IntArray(size()))
}
kotlin 最终会转换为Java字节码,所以可以自行查看字节码,分析