Почему hashCode() из ArrayList изменяется каждый раз, когда вы добавляете новый элемент?

В соответствии с моим пониманием ArrayList, емкость по умолчанию равна 10, а когда она превышает 10, она создаст новый объект с новой емкостью и т.д.

Итак, из любопытства я набрал следующую программу для проверки hashcode() для объекта ArrayList:

public class TestCoreJava {

    public static void main(String [] args){

        ArrayList al = new ArrayList();

        for(int i=0;i<15;i++){

            al.add("Temp"+i);
            System.out.println("Hashcode for "+i+" element "+al.hashCode());
        }
    }
}

В соответствии с вышеприведенным сценарием, когда я не устанавливаю начальную емкость для ArrayList, по умолчанию будет 10. Поэтому, добавляя 11-й элемент, он создаст новый объект и увеличит емкость для ArrayList.

Когда я печатаю хэш-код для объекта ArrayList, он каждый раз дает новый hashcode().

Далее следует o/p:

Hashcode for 0 element 80692955
Hashcode for 1 element -1712792766
Hashcode for 2 element -1476275268
Hashcode for 3 element 1560799875
Hashcode for 4 element 1220848797
Hashcode for 5 element -727700028
Hashcode for 6 element -1003171458
Hashcode for 7 element -952851195
Hashcode for 8 element 607076959
Hashcode for 9 element 1720209478
Hashcode for 10 element -6600307
Hashcode for 11 element -1998096089
Hashcode for 12 element 690044110
Hashcode for 13 element -1876955640
Hashcode for 14 element 150430735

В соответствии с концепцией емкости по умолчанию, до 10-го элемента он должен был напечатать тот же hashcode(), поскольку новый объект не должен быть создан до этой точки, но это не так.

Ответ 1

hashCode ArrayList является функцией hashCode всех элементов, хранящихся в ArrayList, поэтому при изменении емкости он не изменяется, он изменяется всякий раз, когда вы добавляете или удаляете элемент или мутировать один из элементов таким образом, чтобы изменить его hashCode.

Здесь реализация Java 8 (она фактически реализована в AbstractList):

public int hashCode() {
    int hashCode = 1;
    for (E e : this)
        hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
    return hashCode;
}

Кстати, это точный код, который появляется в Javadoc hashCode() интерфейса List:

int java.util.List.hashCode()

Возвращает значение хэш-кода для этого списка. Хэш-код списка определяется как результат следующего вычисления:

int hashCode = 1;
for (E e : list)
    hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());

Ответ 2

hashCode реализаций List определяемый в терминах hashCode его элементов. Это означает, что для ArrayList должна быть соответствующая реализация List, она hashCode должна меняться при изменении ее содержимого.

В более общем плане: для изменяемых объектов hashCode должен меняться, когда они меняются так, чтобы они не equal не переходили в предыдущее состояние.

Предполагается, что он использует default hashCode Object, что не так.

Кроме того, даже если ArrayList не реализовал hashCode, хэш-код по умолчанию (также известный как хэш-код идентификатора) a ArrayList не изменится, если внутренний массив будет переназначен, так как сам объект ArrayList останется прежним, только внутренний объект массива (который вы не получите прямого доступа) будет заменен новым.

Ответ 3

Объяснение этого можно найти, посмотрев документы для hashCode

Если два объекта равны в соответствии с методом equals (Object), то вызов метода hashCode для каждого из двух объектов должен давать одинаковый результат целых чисел.

Когда содержимое ArrayList изменяется, оно также изменяет другие объекты, равные. Чтобы выполнить эту часть договора Object, a ArrayList нужно либо изменить его hashCode, когда содержимое будет, либо иметь каждый ArrayList, тот же hashCode. Чтобы сделать его несколько полезным, они, очевидно, предпочли первое. Это можно проверить, посмотрев List docs.

Возвращает значение хэш-кода для этого списка. Хэш-код списка определяемый как результат следующего вычисления:

 int hashCode = 1;
 for (E e : list)
     hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());

Это гарантирует, что list1.equals(list2) подразумевает, что list1.hashCode() == list2.hashCode() для любых двух списков, list1 и list2, как требуется общим договором Object.hashCode().