关于HashSet的发现:
1:HashSet是一个Set,也就是所谓的集合。集合的概念是元素在集合中无序、唯一。无序对于计算机来说没有什么意义,因为计算机总要按照一定的顺序存储对象。唯一是怎么实现的呢?名字上说的已经很清楚了。HashSet,就是通过其中的元素(对象)的hashconde来区分对象是否唯一的。所以,HashSet的对象中着一个集合中对象的hashcode的list,每次执行set.add(obj)的时候,都会取出obj的hashcode与其内部的list进行比较,如果没有与之相等的,就加进set里去,同时把那个obj的hashcode加到list里面去;如果有相等的,就再调用obj的equals方法与各个对象进行比较,如果没有相等的,就加入到set里面去,如果还有相等的,就不执行加入操作。
public Set add(Object obj){
int code = obj.hashCode(); if(code not in this.hashcodeList){//如果没有于之相等的hashcode。就将obj加入 this.valueList.add(obj); this.hashcodeList.add(code); return true; }else{//否则看看是否有与之equals相等的。 if(code in this.valueList){//有,add失败 return false; }else{//没有,add成功 this.valueList.add(obj); return true; } } } 其实相当于执行了一次contains方法,根据contains方法的返回值决定是否真的add。
也就是说HashSet在确定已经包含某个对象相等的标准是:它们的hashcode相等或者它们的equals方法返回true。
郁闷了半天,怎么先比较hashcode呢?
总算知道了为什么覆盖了toString()后不覆盖hashcode(),Eclipse会给出警告。原来这两个都和对象的相等比较有关系啊。Object的hashcode就是根据对象的内存地址计算出了,保证不重复。而String的hashcode就不一样了,只要字符串的内容相等(equals返回true),它们的hashcode就是相等的。
特别需要注意的是HashSet是有缓存的,第一次contains执行完后会缓存所有的hashcode,以后再调用contains比较的时候使用缓存的hashcode(就是那个list),所以说HashSet最好只用来存储不可变对象,否则contains方法的返回值是不准确的。
一下原则要记住:
1:对于不可变类(String、Integer、以及自己定义的不可变类等),要保证equals返回true的时候,它们的hashcode的值相等。
2:对于不可变类,也要尽量满足1。以避免出现上面说的Set比较时出现的问题。
3:覆盖一个类的equals方法的时候,要注意可交换性,要保证a.equals(b)的值一定等于b.equals(a)的数值。
|
来源:https://www.cnblogs.com/deepnighttwo/archive/2010/07/07/1964336.html