1. 概述
本文将介绍 Kotlin 中 IntArray
和 Array<Int>
的区别。当然,这个区别也适用于其他原始类型数组(如 DoubleArray
, CharArray
等)。
简单来说,**Array<Int>
在底层被编译为 Integer[]
,而 IntArray
被编译为 int[]
**。除非有特殊需求(例如需要支持 null),否则我们应优先使用 IntArray
,因为它更高效。
下面我们将从 JVM 字节码层面深入分析两者的区别。
2. 不同的数组表示方式
在 Kotlin 中,数组分为两种类型:
Array<T>
:泛型数组,T 可以是任意类型,例如Array<String>
或Array<Int>
- 专用原始类型数组:如
IntArray
、DoubleArray
等
之所以存在这两种形式,是因为 JVM 本身支持两种方式创建数组:
newarray
:用于创建原始类型数组(如int[]
),操作时使用iastore
、iaload
等指令anewarray
:用于创建引用类型数组(如Integer[]
),操作时使用aastore
、aaload
等指令
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 压力,建议尽量避免。