The problem goes away when instead of data class I use simply a class or instead of a MutableSet I use an ArrayList. I am trying to understand what is wrong in the way I first wrote it and can't find anything wrong, but it throws a StackOverflow error when running the last line
data class Person(
val id : Int,
val neighbors : MutableSet<Person> = mutableSetOf()
)
fun main() {
val neighbor1 = Person(0)
val commonNeighbor = Person(1)
val neighbor2 = Person(2)
commonNeighbor.neighbors.addAll(listOf(neighbor1,neighbor2))
neighbor1.neighbors.add(commonNeighbor)
neighbor2.neighbors.add(commonNeighbor)
}
CodePudding user response:
(Assuming you are using Kotlin/JVM)
The stack trace makes this a lot clearer. Notice that the stack trace is a repetition of calling these two methods.
at bar.Person.hashCode
at java.base/java.util.AbstractSet.hashCode
Let's consider what happens when you add commonNeighbor
into neighbour2.neighbours
in the final line.
mutableSetOf
creates a linked hash set, and in order to be added to a hash set, commonNeighbour
needs to be hashed.
An implementation of hashCode
is automatically generated for Person
because it is a data class, and this is what is used to hash it. This implementation takes into account (i.e. also calls hashCode
on) the properties declared in Person
's primary constructor, which are id
and neighbours
.
So to hash commonNeighbours
, we need to hash commonNeighbours.id
and commonNeighbours.neighbours
. What neighbours do commonHeighbours
have? neighbour1
and neighbour2
. In order to hash them, we need to hash their neighbours too. But wait! One of neighbour1
's neighbours is commonNeighbours
! We have gone back to where we have started, creating an infinite loop.
All of this wouldn't happen, if the hashCode
of Person
didn't consider neighbours
(which is what making Person
a non-data
class would do), or if you weren't using a HashSet
.