今天写算法,遇到了这个问题:
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)
返回真,所以就不能插入