skip to content

What is the difference between Array<Int> and IntArray in Kotlin, and why does it matter?

level: middleimportance: must knowfreq 75%

answer

  1. Array<Int> = Integer[] (boxed)
  2. IntArray = int[] (unboxed)
  3. primitive = less memory, better cache, no boxing
  4. not subtypes of each other
  5. convert via toTypedArray / toIntArray

basics

~10 s

Array<Int> stores boxed Integer objects; IntArray stores raw int values directly. IntArray uses less memory and is faster because it skips the boxing, so prefer it for numbers.

solid answer

~40 s

On the JVM, Array<Int> compiles to Integer[] — each element is a boxed object with pointer and object overhead. The specialized primitive arrays (IntArray, LongArray, DoubleArray, FloatArray, ShortArray, ByteArray, CharArray, BooleanArray) compile to native int[], long[], etc., storing unboxed primitives contiguously. That means lower memory, better cache locality, and no boxing/unboxing churn in hot loops. Create them with intArrayOf(1,2,3) or IntArray(size) { it }. They share the same [] indexing, .size, and most stdlib operators with Array<T>. The cost: a primitive array is NOT an Array<Int> — they are unrelated types, so a function taking Array<Int> won't accept an IntArray. Convert with toTypedArray() (primitive -> boxed) or toIntArray() (boxed -> primitive). Prefer primitive arrays for numeric data and performance-sensitive code.

code

kotlin · 6 lines
kotlin
val boxed: Array<Int> = arrayOf(1, 2, 3)    // Integer[]
val prim:  IntArray   = intArrayOf(1, 2, 3) // int[], no boxing

fun needsBoxed(a: Array<Int>) {}
// needsBoxed(prim)            // won't compile
needsBoxed(prim.toTypedArray()) // convert int[] -> Integer[]

go deeper

for a junior

Knows IntArray exists and is the right choice for numbers, even if the boxing reasoning is fuzzy.

for a middle

Explains boxed Integer[] vs unboxed int[], the memory/perf consequence, and that the two are not interchangeable types.

for a senior

Adds cache-locality and GC reasoning, the nullability limitation, and the precise conversion functions and Java interop mapping.

for a principal

Sets a default policy (List/primitive arrays for numerics) and weighs micro-optimization against readability across a codebase.

## Two distinct families Kotlin has two array families that look similar but compile very differently: - **`Array<T>`** — the generic array. For `Array<Int>` the JVM erases the generic to **`Integer[]`**: every element is a **boxed** object (an `Integer` instance on the heap, with header + pointer overhead). - **Primitive arrays** — `IntArray`, `LongArray`, `DoubleArray`, `FloatArray`, `ShortArray`, `ByteArray`, `CharArray`, `BooleanArray`. Each maps to the native JVM array `int[]`, `long[]`, `double[]`, etc., storing **unboxed** primitive values packed contiguously. ## Why it matters: boxing **Boxing** wraps a primitive (`int`) into an object (`Integer`). `Array<Int>` forces boxing of every element, costing: - Extra heap memory (object header + reference per element). - Pointer indirection and worse CPU **cache locality**. - Allocation/GC pressure and unbox/rebox work in tight loops. A primitive array avoids all of this — values sit inline, ideal for numeric crunching, buffers, and hot paths. ```kotlin val boxed: Array<Int> = arrayOf(1, 2, 3) // Integer[] val prim: IntArray = intArrayOf(1, 2, 3) // int[] val gen = IntArray(4) { it * it } // [0, 1, 4, 9] ``` ## They are NOT the same type `IntArray` is **not** a subtype of `Array<Int>`. A parameter typed `Array<Int>` will reject an `IntArray` and vice versa: ```kotlin fun sum(xs: Array<Int>) = xs.sum() val p = intArrayOf(1, 2) // sum(p) // compile error sum(p.toTypedArray()) // OK: int[] -> Integer[] val back: IntArray = arrayOf(1, 2).toIntArray() // Integer[] -> int[] ``` ## Shared API Both support `[]` get/set, `.size`, `.indices`, `for` loops, and most stdlib extensions (`map`, `filter`, `sum`, `sorted`). Differences are about element typing, not the surface operations. ## Rule of thumb Use a **primitive array** for numeric/perf-sensitive data. Use `Array<T>` for reference types or when you genuinely need an `Array<Int>` (e.g. nullability `Array<Int?>`, which primitive arrays cannot express).

  • Can you have an IntArray of nullable ints?
    No. Primitive arrays hold unboxed primitives and cannot store null. For nullable ints you need Array<Int?>, which boxes.
  • Does the choice affect interop with Java?
    Yes. IntArray maps to int[] and Array<Int> to Integer[]; Java APIs expecting int[] require IntArray (or a conversion).

Array<Int> is a box of numbers each in its own gift-wrapped parcel; IntArray is the numbers printed straight onto a ruler — no wrapping to unpack.

saying these in an interview costs you the question

  • Saying IntArray is a subtype of Array<Int>
  • Claiming there is no performance difference
  • Thinking IntArray can hold null
  • Not knowing the conversion functions toTypedArray/toIntArray
  • Confusing the element-typing difference with a difference in the [] API

context