Arrays of Generic and Wildcard Types in Kotlin

Kotlin is a modern programming language that offers a powerful type system and concise syntax. Developers coming from Java often look for ways to create arrays using wildcard types such as <?>. While Kotlin handles generics differently, there are several ways to create flexible arrays capable of storing different types of data.

This beginner-friendly guide explains how to create arrays that behave similarly to wildcard arrays in Kotlin and when to use each approach.

Understanding Wildcards in Kotlin

In Java, you might encounter wildcard types such as:

List<?>

Kotlin does not use the ? wildcard syntax in the same way. Instead, it provides:

  • Any
  • Any?
  • Star projections (*)
  • Generic type parameters

These features allow developers to achieve the same flexibility while maintaining type safety.


Using Array<Any?>

The simplest approach is to create an array that can store any type of value.

val values: Array<Any?> = arrayOf(
    "Hello",
    123,
    true,
    45.67,
    null
)

Output

Hello
123
true
45.67
null

This array can contain:

  • Strings
  • Numbers
  • Booleans
  • Objects
  • Null values

Because Any? is the root type of all nullable objects in Kotlin.


Creating an Empty Generic Array

Sometimes you need an array that will be populated later.

val data: Array<Any?> = arrayOfNulls(5)

This creates:

[null, null, null, null, null]

You can then populate it:

data[0] = "Kotlin"
data[1] = 100
data[2] = false

Creating Arrays with Generic Functions

A more reusable approach is to create a generic function.

inline fun <reified T> createArray(size: Int): Array<T?> {
    return arrayOfNulls(size)
}

Usage:

val strings = createArray<String>(3)
val numbers = createArray<Int>(5)

Result:

[String?, String?, String?]
[Int?, Int?, Int?, Int?, Int?]

This allows the same method to create arrays for any data type.


Using Star Projections

Kotlin provides star projections (*) as the closest equivalent to Java wildcards.

Example:

val list: List<*> = listOf(
    "Text",
    123,
    true
)

This means:

A list of unknown type

You can read values safely:

for (item in list) {
    println(item)
}

Output:

Text
123
true

Working with Arrays of Unknown Types

You can also declare:

val array: Array<*> = arrayOf(
    "Apple",
    "Orange",
    "Banana"
)

Or:

val mixedArray: Array<*> = arrayOf(
    "Hello",
    42,
    true
)

When using Array<*>, Kotlin allows safe reading but restricts writing because the exact type is unknown.


Difference Between Any? and *

Many developers confuse these two concepts.

Array<Any?>

val arr: Array<Any?> = arrayOf("A", 1, true)

Characteristics:

  • Can store any value.
  • Allows writing new values.
  • Explicitly uses Any? as the type.

Array<*>

val arr: Array<*> = arrayOf("A", "B", "C")

Characteristics:

  • Represents an unknown type.
  • Safe for reading.
  • Restricts writing operations.

Practical Example

Suppose you are processing data from different sources:

val records: Array<Any?> = arrayOf(
    "John",
    25,
    true,
    1500.75
)

for (record in records) {
    println(record)
}

Output:

John
25
true
1500.75

This approach is useful when:

  • Reading CSV files
  • Processing API responses
  • Creating dynamic data structures
  • Logging heterogeneous data

Common Mistakes

Using Array<String> When Types Differ

Incorrect:

val arr: Array<String> = arrayOf(
    "Hello",
    123
)

Compilation error occurs because all elements must be strings.

Correct

val arr: Array<Any?> = arrayOf(
    "Hello",
    123
)

Forgetting Nullability

Incorrect:

val arr: Array<Any> = arrayOf(
    "Hello",
    null
)

This causes an error because Any cannot hold null values.

Correct

val arr: Array<Any?> = arrayOf(
    "Hello",
    null
)

Performance Considerations

For primitive values, Kotlin provides specialized arrays:

val numbers = intArrayOf(1, 2, 3)

Instead of:

val numbers = arrayOf(1, 2, 3)

Specialized arrays avoid boxing and typically provide better performance.

Examples:

IntArray
LongArray
DoubleArray
BooleanArray
CharArray

Best Practices

Use Any? When

  • Multiple data types must coexist.
  • Dynamic structures are required.
  • Null values are expected.

Use Generic Arrays When

  • Strong typing is important.
  • Reusable utility functions are needed.
  • Compile-time safety is desired.

Use Star Projections (*) When

  • The exact type is unknown.
  • You only need read access.
  • Working with generic APIs.

Conclusion

Although Kotlin does not use Java-style wildcard syntax such as <?>, it provides several powerful alternatives. Developers can use Any? for mixed-type arrays, generic functions for reusable type-safe arrays, and star projections (*) when working with unknown generic types.

Understanding these options helps create cleaner, safer, and more maintainable Kotlin applications while taking full advantage of Kotlin’s modern type system.

This article is inspired by real-world challenges we tackle in our projects. If you're looking for expert solutions or need a team to bring your idea to life,

Let's talk!

    Please fill your details, and we will contact you back

      Please fill your details, and we will contact you back