skip to content

Explain how Array<Int>, IntArray, and List<Int> each map to Java types, and why Kotlin provides separate specialized array types.

level: seniorimportance: should knowfreq 35%

answer

  1. Array<Int> → Integer[] (boxed)
  2. IntArray → int[] (primitive, no boxing)
  3. List<Int> → List<Integer> (boxed)
  4. Specialized arrays exist because generics can't hold primitives
  5. Convert: toIntArray / toTypedArray / toList

basics

~10 s

Array<Int> becomes Integer[] (boxed objects), IntArray becomes the primitive int[], and List<Int> becomes a java.util.List of Integer. Kotlin has specialized arrays like IntArray so numeric data can stay as fast primitive arrays without boxing.

solid answer

~30 s

Array<Int> maps to java.lang.Integer[] — boxed, because a generic Array<T> erases to a reference array. IntArray maps to the JVM primitive int[] with no boxing, which is why Kotlin ships IntArray, LongArray, DoubleArray, etc., as distinct types: they expose the performance of primitive arrays that generics can't. List<Int> maps to java.util.List<Integer> (also boxed; generics are reference-only on the JVM). So for numeric performance you reach for IntArray/intArrayOf; for object data or the collection API you use Array<T>/List<T>. Mapped collection interfaces (List/Set/Map) still cover the collection side; arrays are the primitive-friendly escape hatch.

code

kotlin · 7 lines
kotlin
val a: IntArray = intArrayOf(1, 2, 3)     // int[]
val b: Array<Int> = arrayOf(1, 2, 3)      // Integer[]
val c: List<Int> = listOf(1, 2, 3)        // List<Integer>

// Conversions across the forms
val back: IntArray = c.toIntArray()       // List<Integer> -> int[]
val boxed: Array<Int> = a.toTypedArray()  // int[] -> Integer[]

go deeper

for a junior

Knows IntArray is the fast primitive array and List<Int> uses the collection API.

for a middle

Correctly maps all three forms to int[]/Integer[]/List<Integer> and explains boxing.

for a senior

Chooses IntArray vs List<Int> by performance/interop needs and knows the conversion functions and their cost.

for a principal

Reasons about memory layout, GC pressure, and API ergonomics when designing numeric-heavy interop surfaces and large buffers.

## Three different runtime shapes | Kotlin | JVM type | Boxing? | |--------|----------|---------| | `Array<Int>` | `java.lang.Integer[]` | Yes (objects) | | `IntArray` | `int[]` (primitive array) | No | | `List<Int>` | `java.util.List<Integer>` | Yes (objects) | ## Why Array<Int> is boxed `Array<T>` is **generic**. JVM generics are erased to reference types, and a reference array of `Int` is an array of the boxed type — `Integer[]`. Every element is a heap object. ## Why IntArray exists The JVM has true **primitive arrays** (`int[]`, `long[]`, `double[]`, …) that store raw values contiguously — no per-element object, no boxing, cache-friendly, fast. Kotlin can't express `Array<int>` (you can't use a primitive as a generic argument), so it provides **specialized array classes** that map directly to those primitive arrays: - `IntArray` → `int[]` - `LongArray` → `long[]` - `DoubleArray` → `double[]` - `BooleanArray` → `boolean[]`, `CharArray` → `char[]`, `ByteArray` → `byte[]`, `ShortArray` → `short[]`, `FloatArray` → `float[]` Factory helpers: `intArrayOf(1, 2, 3)`, `IntArray(n) { it }`. ## Why List<Int> is boxed `List<Int>` is a generic collection; type arguments must be references, so it's `List<Integer>`. Convenient and rich (collection API, read-only views) but each element is boxed. ## Choosing ```kotlin val fast: IntArray = intArrayOf(1, 2, 3) // int[] — numeric hot loops val boxedArr: Array<Int> = arrayOf(1, 2, 3) // Integer[] — rarely what you want for numbers val list: List<Int> = listOf(1, 2, 3) // List<Integer> — collection ops, read-only view ``` - **Hot numeric code / large numeric buffers** → `IntArray` & friends (no boxing, contiguous memory). - **Need the collection API, transformations, read-only semantics** → `List<Int>` (boxed but ergonomic). - **Array of objects** → `Array<T>`. ## Interop angle A Java method taking `int[]` accepts `IntArray` directly; one taking `Integer[]` accepts `Array<Int>`; one taking `List<Integer>` accepts `List<Int>`. Picking the wrong Kotlin type forces a conversion (`toIntArray()`, `toTypedArray()`, `toList()`).

  • If a Java API expects int[], can you pass a List<Int> directly?
    No. List<Int> is List<Integer>; you must convert with toIntArray() to get the primitive int[] the Java method requires.
  • Why might Array<Int> be a performance pitfall for numeric code?
    It's Integer[] — every element is a boxed heap object, costing allocations and cache misses. IntArray (int[]) avoids all that for the same numbers.

IntArray is a tray of raw coins lined up tightly; Array<Int> and List<Int> are boxes where each coin sits in its own gift box — easier to label but heavier and slower to handle.

saying these in an interview costs you the question

  • Claiming Array<Int> maps to int[]
  • Saying IntArray is boxed
  • Thinking List<Int> can hold primitives
  • Believing you can write Array<int> in Kotlin
  • Passing List<Int> where Java wants int[] without conversion

context