1. 概述

本文将介绍 Kotlin 中 IntArrayArray<Int> 的区别。当然,这个区别也适用于其他原始类型数组(如 DoubleArray, CharArray 等)。

简单来说,**Array<Int> 在底层被编译为 Integer[],而 IntArray 被编译为 int[]**。除非有特殊需求(例如需要支持 null),否则我们应优先使用 IntArray,因为它更高效。

下面我们将从 JVM 字节码层面深入分析两者的区别。

2. 不同的数组表示方式

在 Kotlin 中,数组分为两种类型:

  • Array<T>:泛型数组,T 可以是任意类型,例如 Array<String>Array<Int>
  • 专用原始类型数组:如 IntArrayDoubleArray

之所以存在这两种形式,是因为 JVM 本身支持两种方式创建数组:

  • newarray:用于创建原始类型数组(如 int[]),操作时使用 iastoreiaload 等指令
  • anewarray:用于创建引用类型数组(如 Integer[]),操作时使用 aastoreaaload 等指令

JVM 对原始类型数组有专门的优化指令,因此效率更高。

接下来我们通过字节码来验证这两种数组在 JVM 中的实现差异。

3. Array<Int> 的字节码表示

我们来看一段 Kotlin 代码:

val arrayOfInts = arrayOf<Int>(42)

这段代码创建了一个 Array<Int>,并初始化一个元素 42

编译后,使用 javap -c -p 查看字节码:

0: iconst_1
1: anewarray     #8      // class java/lang/Integer

结论:Array<Int> 被编译为 Integer[],即引用类型数组。

接着看如何将 42 存入数组:

6: iconst_0
7: bipush        42
9: invokestatic  #12    // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
12: aastore

⚠️ 注意:JVM 调用 Integer.valueOf()int 包装为 Integer,也就是发生了自动装箱(boxing)操作。频繁操作 Array<Int> 会导致大量装箱操作,影响性能。

4. IntArray 的字节码表示

我们再来看 IntArray 的写法:

val intArray = intArrayOf(42)

同样编译后查看字节码:

15: iconst_1
16: newarray   int

结论:IntArray 被编译为 int[],即原始类型数组。

再看元素赋值部分:

20: iconst_0
21: bipush     42
23: iastore

⚠️ 注意:这里没有调用任何包装类方法,直接将 int 存入数组,没有装箱操作。效率更高。

5. 总结

对比项 Array<Int> IntArray
类型 引用类型数组 原始类型数组
JVM 表示 Integer[] int[]
装箱操作
支持 null
推荐场景 需要 null 值时 默认首选

推荐做法:除非需要 null 值,否则应优先使用 IntArray 这类专用原始数组类型,以避免不必要的装箱和提升性能。

⚠️ 踩坑提醒:在性能敏感的场景下(如高频数据处理、游戏循环等),使用 Array<Int> 会引入额外的 GC 压力,建议尽量避免。


原始标题:IntArray vs Array in Kotlin