
Image generated by the author using Midjourney
In a previous article, we discussed why using var
in the constructor of a Kotlin data class
can lead to unexpected behavior and subtle bugs.
Now, let’s look at another important detail that often goes unnoticed:
why you should avoid using Array
types in the constructor of a data class
.
Kotlin’s data class
feature simplifies the creation of immutable models by automatically generating equals()
, hashCode()
, copy()
, and toString()
based on the primary constructor properties.
For most use cases, this behavior works exactly as expected.
However, when you use an Array
as a property, the behavior of equals()
, hashCode()
, and toString()
may not match your intentions.
Instead of comparing the contents of the array, Kotlin (and Java) compare the object references.
This can lead to subtle and hard-to-detect bugs — especially when your data classes are used in sets, maps, or caching systems.
In this article, we’ll see why using Array
inside a data class
constructor is risky, and what you should do instead.
Featured On
Working correctly with List
Let’s start with a simple example where the friends
property is a List
inside a data class:
data class Person( val name: String, val friends: List<String> ) fun main() { val person1 = Person( name = "Mike", friends = listOf("Mary", "John", "Tom") ) val person2 = Person( name = "Mike", friends = listOf("Mary", "John", "Tom") ) println(person1 == person2) }
Output:
true
In this case, the two Person
instances are considered equal.
This is because List
in Kotlin overrides equals()
and hashCode()
to compare the contents of the list, not just the object references.
Two lists are considered equal if:
- They contain the same elements,
- In the same order.
As a result, Kotlin’s generated equals()
and hashCode()
for the data class properly compare the friends
list by value.
Problem when using Array
Now, let’s modify the example slightly by changing the friends
property to use an Array
instead of a List
:
data class Person( val name: String, val friends: Array<String> ) fun main() { val person1 = Person( name = "Mike", friends = arrayOf("Mary", "John", "Tom") ) val person2 = Person( name = "Mike", friends = arrayOf("Mary", "John", "Tom") ) println(person1 == person2) }
Output:
false
Even though both Person
instances have the same name
and the same friends
, the comparison returns false
.
This happens because Array
in Kotlin (and Java) does not override equals()
and hashCode()
to compare the contents of the array.
In contrast, collections like List
, Set
, and Map
correctly override these methods to compare contents structurally in both Kotlin and Java.
Instead, Array
uses reference equality — two arrays are considered equal only if they are the same instance in memory.
As a result, even identical-looking objects are treated as different when arrays are involved.
IDE warning
Modern IDEs like Android Studio and IntelliJ IDEA can detect this potential problem.
If you declare an Array
as a property inside a data class
, the IDE will highlight it with a warning:
Property with ‘Array’ type in a ‘data’ class: it is recommended to override equals() and hashCode()
This warning is a strong signal that using arrays inside data classes can easily lead to incorrect or unpredictable behavior — even if the code compiles without errors.
Why this causes real issues
In some cases, data class
instances are used as keys in HashMap
or as elements in HashSet
.
Both collections rely on consistent implementations of hashCode()
and equals()
to work correctly.
When a data class
contains an Array
, these operations are based on the reference of the array, not its contents.
This leads to problems such as:
- Cache misses when using objects as keys in maps,
- Duplicate entries in sets,
- Incorrect behavior in collections that expect structural equality.
Even if two objects have identical data, the program treats them as different — simply because their arrays are different instances in memory.
Job Offers
How to avoid this problem
The solution is simple: avoid using Array
types inside the primary constructor of a data class
.
Instead, use collection types that correctly override equals()
and hashCode()
, such as List
, Set
, or Map
.
These types compare their contents structurally, not by reference, and fully support the behavior expected from data classes.
Choosing the right types ensures that equality checks, hashing, and collection behavior work as intended — even in large and complex applications.
Conclusion
Kotlin’s data class
feature automatically generates equals()
, hashCode()
, and other utility methods based on the properties declared in the primary constructor.
This works reliably — as long as the types used behave correctly.
Array
types in Kotlin (and Java) do not override equals()
and hashCode()
to compare contents.
Instead, they use reference equality, which can lead to subtle and hard-to-detect bugs when comparing objects or working with collections.
Modern IDEs like Android Studio can warn you about this issue.
But they cannot explain why it happens, what consequences it brings, or how to design safer models.
Understanding these details helps not only to fix isolated problems,
but also to build predictable, safe, and maintainable data models as your applications grow.
When working with collections inside a data class
, prefer List
, Set
, or Map
instead of Array
.
Choosing the right types is a small decision that helps prevent much larger problems later.
If you found this article helpful
If you enjoyed this article or learned something new, consider leaving a clap — it helps others discover it.
You can also follow me on Medium for more articles about Kotlin, Android development, and practical engineering topics.
You might also like:

Anatolii Frolov
Senior Android Developer
Writing honest, real-world Kotlin & Jetpack Compose insights.
📬 Follow me on Medium
This article was previously published on proandroiddev.com.