Can we find the hashcode
of a list
that contains itself as element
?
I know this is a bad practice, but this is what the interviewer asked.
When I ran the following code it throws a StackOverflowError
:
public class Main {
public static void main(String args[]) {
ArrayList<ArrayList> a = new ArrayList();
a.add(a);
a.hashCode();
}
}
Now here I have two questions:
StackOverflowError
?The hashCode of List implementations is defined in terms of the hashCode of its elements. This means that for ArrayList to be a conforming List implementation it's hashCode must change when its content changes.
hashCode(Object[]) method returns a hash code based on the contents of the specified array. If the array contains other arrays as elements, the hash code is based on their identities rather than their contents. For any two arrays a and b such that Arrays. equals(a, b), it is also the case that Arrays.
The hashCode method is an inbuilt method that returns the integer hashed value of the input value. Here are a few key concepts to remember: Multiple invocations of the hashCode must return the same integer value within the execution of a program unless the Object used within the equals method changes.
Java Object hashCode() is a native method and returns the integer hash code value of the object. The general contract of hashCode() method is: Multiple invocations of hashCode() should return the same integer value, unless the object property is modified that is being used in the equals() method.
The hash code for conforming List
implementations has been specified in the interface:
Returns the hash code value for this list. The hash code of a list is defined to be the result of the following calculation:
int hashCode = 1; for (E e : list) hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
This ensures that
list1.equals(list2)
implies thatlist1.hashCode()==list2.hashCode()
for any two lists,list1
andlist2
, as required by the general contract ofObject.hashCode()
.
This doesn’t require that the implementation looks exactly like that (see How to compute the hash code for a stream in the same way as List.hashCode() for an alternative), but the correct hash code for a list only containing itself would be a number for which x == 31 + x
must be true
, in other words, it is impossible to calculate a conforming number.
Check out the skeletal implementation of the hashCode
method in AbstractList
class.
public int hashCode() {
int hashCode = 1;
for (E e : this)
hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
return hashCode;
}
For each element in the list, this calls hashCode
. In your case list has itself as it's sole element. Now this call never ends. The method calls itself recursively and the recursion keeps winding until it encounters the StackOverflowError
. So you can not find the hashCode
this way.
You have defined a (pathological) list that contains itself.
Why there is
StackOverflowError
?
According to the javadocs (i.e. the specification), the hashcode of a List
is defined to a function of the hashcode of each of its elements. It says:
"The hash code of a list is defined to be the result of the following calculation:"
int hashCode = 1; for (E e : list) hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
So to compute the hashcode of a
, you first compute the hashcode of a
. That is infinitely recursive and leads quickly to a stack overflow.
Is it possible to find hash code in this way ?
No. If you consider the algorithmic specification above in mathematical terms, the hashcode of a List
that contains itself is a non-computable function. It is not possible to compute it this way (using the above algorithm) or any other way.
The documentation of the List structure explicitly states:
Note: While it is permissible for lists to contain themselves as elements, extreme caution is advised: the equals and hashCode methods are no longer well defined on such a list.
There's not much more to say beyond that - according to the Java specification, you won't be able to calculate hashCode for a list that contains itself; other answers go into detail why it's so, but the point is that it is known and intentional.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With