Kotlin 提高篇——数组

数组

先来谈谈数组,也可参考 Kotlin 快速入门#数组

数组在 Kotlin 中使用 Array 类来表示,它定义了 getset 函数(按照运算符重载约定这会转变为 [])和 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.ktarrayOf() 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<String>赋值给 Array<Any>,以防止可能的运行时失败(但是你可以使用 Array<out Any>, 参见类型投影)。

之前所说的在泛型情况下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<T> 对象进行迭代:

 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 背后实现

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<T : Any>(private val size: Int) 对象,以及基本类型的对应的子对象 ByteSpreadBuilder、CharSpreadBuilder、DoubleSpreadBuilder、FloatSpreadBuilder、IntSpreadBuilder、LongSpreadBuilder、ShortSpreadBuilder、BooleanSpreadBuilder 看完源码后,直到关注的只有3个点

  • 单个基本类型元素的添加,都是IntSpreadBuilder 等子类add(value: Int)实现的,并保存到values 相关类型数组集合里面
  • 单个基本类型数组元素添加,都是PrimitiveSpreadBuilder 基类addSpread(spreadArgument: T) 实现的,并保存到 spreads 数组集合里面
  • toArray(values: T, result: T): T 该函数在基类里完成values、spreads数据拷贝到result 数组中
public abstract class PrimitiveSpreadBuilder<T : Any>(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<T?> = arrayOfNulls<Any>(size) as Array<T?>
	//添加数组到相应位置
    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<IntArray>(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字节码,所以可以自行查看字节码,分析

欢迎扫一扫!
11547476583_.pic.jpg

猜你喜欢

转载自blog.csdn.net/CSDNno/article/details/79594505
今日推荐