目录
Integer
核心代码
/**
* Returns a hash code for this {@code Integer}.
*
* @return a hash code value for this object, equal to the
* primitive {@code int} value represented by this
* {@code Integer} object.
*/
@Override
public int hashCode() {
return Integer.hashCode(value);
}
/**
* Returns a hash code for a {@code int} value; compatible with
* {@code Integer.hashCode()}.
*
* @param value the value to hash
* @since 1.8
*
* @return a hash code value for a {@code int} value.
*/
public static int hashCode(int value) {
return value;
}
本质就是返回原值
String
核心代码
/**
* Returns a hash code for this string. The hash code for a
* {@code String} object is computed as
* <blockquote><pre>
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
* </pre></blockquote>
* using {@code int} arithmetic, where {@code s[i]} is the
* <i>i</i>th character of the string, {@code n} is the length of
* the string, and {@code ^} indicates exponentiation.
* (The hash value of the empty string is zero.)
*
* @return a hash code value for this object.
*/
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i]; // 31 * 高位到低位
}
hash = h;
}
return h;
}
以字符串"123"为例:
字符'1'的ascii码是49
hashCode = (49*31 + 50)*31 + 51
或者这样看:
hashCode=('1' * 31 + '2' ) * 31 + '3'
可见实际可以看作是一种权重的算法,在前面的字符的权重大。
这样有个明显的好处,就是前缀相同的字符串的hash值都落在邻近的区间。
好处有两点:
1.可以节省内存,因为hash值在相邻,这样hash的数组可以比较小。比如当用HashMap,以String为key时。
2.hash值相邻,如果存放在容器,比好HashSet,HashMap中时,实际存放的内存的位置也相邻,则存取的效率也高。(程序局部性原理)
以31为倍数,原因了31的二进制全是1,则可以有效地离散数据。
"123".equals("123") // 结果是 true
类
举例
hashCode 应该是类的地址
static class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
HashMapTest.Person person2 = new HashMapTest.Person("name2", 22);
HashMapTest.Person person3 = new HashMapTest.Person("name2", 22);
person2.equals(person3) // 如果没有重写 equals 方法以及 hashCode 方法,结果是 false,比较的是地址,与 "==" 效果一样
// person2 和 person3 放入到 HashSet 里面是两个对象
重写 equals
static class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override public boolean equals(Object obj) {
// 同一对象,返回 true
if (this == obj) return true;
// 不同类,返回 false
if (!(obj instanceof Person))
return false;
Person person = (Person) obj;
return person.name == name && person.age == age;
}
}
System.out.println(person2.hashCode());
System.out.println(person3.hashCode());
if(person2.equals(person3)) {
System.out.println("equals");
}
HashMap<HashMapTest.Person, Integer> hashMap = new HashMap<>();
hashMap.put(person2, 2);
System.out.println(hashMap.get(person3));
结果
equals 但是 hashCode 不一样,因为 hashCode 应该还是地址,放入到 HashMap 里面是找不到的
重写 hashCode 方法
@Override public int hashCode() {
int result;
result = 17;
result = 31 * result + age;
result = result + name.hashCode();
return result;
}
结果
equals 并且 hashCode 一样