第一,继承关系;
AbstractSet 抽象类,实现了hashCode、equals 这两个比较时需要用到的方法
|---------------HashSet
|--------------LinkedHashSet
|---------------TreeSet
第二,顺序性;
集合(Set)表面看起来存储空间分布及输出都是无序的,我们很多时候会先入为主地认为顺序应该就是自己加入集合的顺序或倒序。
实际上存储位置决定于其hashCode值,是有序,其最终顺序就是hash值的顺序,在堆空间中也是连续分布的。
第三,hash方法的实现;
AbstrackSet的hashCode方法源码如下:
/**
* Returns the hash code value for this set. The hash code of a set is
* defined to be the sum of the hash codes of the elements in the set,
* where the hash code of a <tt>null</tt> element is defined to be zero.
* This ensures that <tt>s1.equals(s2)</tt> implies that
* <tt>s1.hashCode()==s2.hashCode()</tt> for any two sets <tt>s1</tt>
* and <tt>s2</tt>, as required by the general contract of
* {@link Object#hashCode}.
*
* <p>This implementation iterates over the set, calling the
* <tt>hashCode</tt> method on each element in the set, and adding up
* the results.
*
* @return the hash code value for this set
* @see Object#equals(Object)
* @see Set#equals(Object)
*/
public int hashCode() {
int h = 0;
Iterator<E> i = iterator();
while (i.hasNext()) {
E obj = i.next();
if (obj != null)
h += obj.hashCode();
}
return h;
}
由此可见,hash值实际上是整型值。算法是将各个非空元素的hash值相加得来。
猜想,是不是存在一些出问题的可能性:集合的每一个元素可能是不同的对象,不同对象自身的hash值算法,由于程序员重写,可能不尽相同,但是结果却可能相同,从而出现总和计算相同,而实际对象不一致的情况。
对于自定义hashCode可以按如下思路来编写:
public int hashCode() {
final int prime = 31;
int result = 1;
// voucher是目标对象
try{
//通过getDeclaredFields()方法获取对象类中的所有属性(含私有)
Field[] fields = voucher.getClass().getDeclaredFields();
for (Field field : fields) {
//设置允许通过反射访问私有变量
field.setAccessible(true);
//获取字段的值
//String value = field.get(voucher).toString();
//获取字段属性名称
//String name = field.getName();
result = prime * result + ((field == null) ? 0 : field.hashcode);
}
return result;
}
catch (Exception ex) {
//处理异常
}
}
如上代码,如果对象属性还是自定义类,则其自定义类也必须有其自己的hashCode。