如果一个类的对象要用做hashMap的key,那么一定要注意覆盖该类的equals和hashCode方法。
equals()是基类Object的方法,用于判断对象是否有相同地址及是否为同一对象
public boolean equals(Object obj) { return (this == obj); }
hashCode()是基类Object的native方法,返回int。
hashCode的通用约定:
1.在程序运行期间,只要对象不改变,hashCode方法返回的值始终如一。
2.若两个对象equals方法返回相同,hashCode也应该相同。
3.若两个对象equals方法返回不同,hashCode也应该不同。
根据上面的约定,覆盖hashCode方法时注意:
1.需使用对象属性中关键且独立的部分
2.不要使用equals方法中未使用的属性
3.使用equals方法中使用的属性
String类的hashCode方法:
1 public int hashCode() { 2 int h = hash; 3 if (h == 0 && value.length > 0) { 4 char val[] = value; 6 for (int i = 0; i < value.length; i++) { 7 h = 31 * h + val[i]; 8 } 9 hash = h; 10 } 11 return h; 12 }
32*d == d<<5 aka 31*d == d<<5-d
一个例子:
----------------------------
1 class TestClass { 2 // 若类较复杂,建议将hashCode缓存,以提高性能 3 private volatile int hashCode = 0; 4 5 private int i; 6 private boolean b; 7 private char c; // 或byte short 8 private long l; 9 private float f; 10 private double d; 11 private int[] aa; 12 private String s; 13 14 @Override 15 public boolean equals(Object o) { 16 if (o == this) { 17 return true; 18 } 19 if (!(o.getClass() == getClass())) { 20 return false; 21 } 22 TestClass ot = (TestClass) o; 23 return i == ot.i && b == ot.b && c == ot.c && l == ot.l && Float.compare(f, ot.f) == 0 && Double.compare(d, ot.d) == 0 24 && Arrays.equals(aa, ot.aa) && s.equals(ot.s); 25 } 26 27 @Override 28 public int hashCode() { 29 int result = hashCode; 30 if (result == 0) { 31 result = 31 * result + i; 32 result = 31 * result + Boolean.hashCode(b); 33 result = 31 * result + (int)c; 34 result = 31 * result + Long.hashCode(l); 35 result = 31 * result + Float.hashCode(f); 36 result = 31 * result + Double.hashCode(d); 37 result = 31 * result + Arrays.hashCode(aa); 38 result = 31 * result + s.hashCode(); 39 hashCode = result; 40 } 41 return result; 42 } 43 44 @Override 45 public String toString(){ 46 //略 47 return s; 48 } 49 50 }
----------------------------
HashMap
HashMap默认初始容量16,加载因子0.75,容量也就是内部数组table的大小,总是2的n次方,table中的元素为链表,链表的元素为包含key,value,hash和下一元素的Entry。
put方法根据key的hashCode来计算元素在table中的存放位置,不同的key将均匀的散列在table中。
HashMap的扩容将重新计算所有元素在新数组中的位置,所以如果预计存放大量数据,初始容量应该设置更大。