web-dev-qa-db-ja.com

新しい要素を追加するたびにArrayListのhashCode()が変更されるのはなぜですか?

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()を出力するはずですが、そうではありません。

19
suyash

hashCodeArrayListは、hashCodeに格納されているすべての要素のArrayListsの関数であるため、容量が変化しても変化しません。要素を追加または削除するか、hashCodeを変更する方法で要素の1つを変更するたびに変更されます。

Java 8実装です(実際にはAbstractListに実装されています):

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

ところで、これはListインターフェースのhashCode()のJavadocに表示される正確なコードです。

int Java.util.List.hashCode()

このリストのハッシュコード値を返します。リストのハッシュコードは、次の計算の結果として定義されます。

_int hashCode = 1;
for (E e : list)
    hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
_
42
Eran

hashCodeListの実装は その要素のhashCodeで定義 です。これは、ArrayListが準拠するList実装であるためには、hashCodemustコンテンツが変更されたときに変更されることを意味します。

より一般的には、可変オブジェクトの場合、hashCodeは、以前の状態にequalしないように変更されるたびに変更する必要があります。

default hashCode of Objectを使用すると想定しているようですが、そうではありません。

さらに、ArrayListhashCodeを実装していなくても、ArrayListのデフォルトのハッシュコード(別名 identity hash code )はArrayListオブジェクト自体は同じままなので、内部配列が再割り当てされた場合は変更し、内部配列オブジェクト(直接アクセスできない)だけを新しい配列オブジェクトに置き換えます。

5
Joachim Sauer

これの説明は hashCodeのドキュメント を参照してください。

Equals(Object)メソッドに従って2つのオブジェクトが等しい場合、2つのオブジェクトのそれぞれでhashCodeメソッドを呼び出すと、同じ整数の結果が生成される必要があります。

ArrayListsの内容が変更されると、それが等しい他のオブジェクトも変更されます。 Objectの契約のこの部分を満たすために、ArrayListは、内容が変化したときにhashCodeを変更するか、すべてのArrayListを保持する必要があります同じhashCodeです。それをいくらか有用にするために、彼らは明らかに前者を選びました。これは Listのドキュメント で確認できます。

このリストのハッシュコード値を返します。リストのハッシュコードは、次の計算の結果として定義されます。

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

これにより、Object.hashCode()の一般規約で要求されるように、list1.equals(list2)が2つのリスト、list1とlist2のlist1.hashCode()== list2.hashCode()を暗黙的に示すことが保証されます。

2
resueman