1. 程式人生 > >Java中hashset底層實現機制

Java中hashset底層實現機制

今天寫演算法,遇到了這個問題:
HashSet<int[]> hs = new HashSet<>();
int[] arr1 = {4,5};
int[] arr2 = {4,5};
hs.add(arr1);
hs.add(arr2);
System.out.println(hs.size());
結果為:2
HashSet<ArrayList<Integer>> hs = new HashSet<>();
ArrayList<Integer> arr1 = new ArrayList<>(){{add(4);add(5)}};
ArrayList<Integer> arr2 = new ArrayList<>(){{add(4);add(5)}};
hs.add(arr1);
hs.add(arr2);
System.out.prinln(hs.size());
輸出為:1原因:
HashSet的底層是用hashmap實現的,用到了物件的equals方法和hashcode值例如,當要add一個新物件時,先計算他的hashcode值,根據hashcode值,插入到hashmap合適的位置中,如果位置上有元素,則採用equals方法比較,如果相同不插入,如果不相同,新找一個位置插入如果位置上沒有元素,則直接插入。因此,當插入新元素時,如果這個元素和已存中的某一個元素(any)的hashcode相同且equals()返回為真,那麼就不能插入備註:除非你重寫了equals方法, 否則,equals為真的兩元素,其hashcode也一定相同那麼我遇到的問題也好解決了:第一種情況,兩個都是Int陣列,arr1和arr2的hashcode就不相同,arr2找到的hashmap中的位置與arr1就不相同,不需要用equals方法,arr2就可以插入.第二種情況,兩個是arraylist,arr2的hashcode和arr1的hashcode相同,有興趣的同學可以去看一下AbstactList.java中HashCode()方法,到底是怎麼計算arraylist的hashcode值,這裡我貼出來
public int hashCode() {
        int hashCode = 1;
        for (E e : this)
            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
        return hashCode;
    }
因為hashcode值相同,則找到了相同的位置,於是使用equals()方法,arraylist的equals方法如下:
 public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof List))
            return false;

        ListIterator<E> e1 = listIterator();
        ListIterator<?> e2 = ((List<?>) o).listIterator();
        while (e1.hasNext() && e2.hasNext()) {
            E o1 = e1.next();
            Object o2 = e2.next();
            if (!(o1==null ? o2==null : o1.equals(o2)))
                return false;
        }
        return !(e1.hasNext() || e2.hasNext());
    }
對每一個元素呼叫其equals方法,都為true就返回為真,所以這一看一下Integer的equal()
public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }
Integer的equals方法,值相同則返回為真,所以arr2和arr1中依次迴圈比較,每個值得equals都返回為真,則arr2.equals(arr1)返回真,所以就不能插入