想要了解hashCode(),可以先了解下hash
-
hash和hash表
可以看下百度的定义:
Hash(散列函数),一般翻译做散列、杂凑,或音译为哈希,是把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
- hash: 可以看出hash其实就是是一个函数,该函数中的实现就是一种算法,就是通过一系列的算法来得到一个hash值
- hash表: 就通过hash算法得到的hash值就在这张hash表中,也就是说,hash表就是所有的hash值组成的,有很多种hash函数,也就代表着有很多种算法得到hash值
2. hashcode
首先一个对象肯定有物理地址,然而对象的物理地址跟hashcode地址不同,hashcode代表对象的地址说的是对象在hash表中的位置,物理地址说的对象存放在内存中的地址
那么对象如何得到hashcode呢?
其实就是通过对象的内部地址(也就是物理地址)转换成一个整数,然后该整数通过hash函数的算法就得到了hashcode。
举个例子,hash表中有这样八个位置
1 2 3 4 5 6 7 8
假设有一个对象A,A的物理地址转换为一个整数17,就通过直接取余算法,17%8=1,那么A的hashcode就为1,且A就在hash表中1的位置
3.hashcode作用
在Java中,有一些哈希容器,比如Hashtable,HashMap等等。当我们调用这些容器的诸如get(Object obj)方法时,容器的内部肯定需要判断一下当前obj对象在容器中是否存在,然后再进行后续的操作。一般来说,判断是够存在,肯定是要将obj对象和容器中的每个元素一一进行比较,要使用equals()才是正确的。
但是如果哈希容器中的元素有很多的时候,如果采用equals方法去逐一比较,效率必然是一个问题。此时hashCode方法的作用就体现出来了:当我们调用哈希容器的get(Object obj)方法时,它会首先利用查看当前容器中是否存在有相同哈希值的对象,如果不存在,那么直接返回null;如果存在,再调用当前对象的equals()方法比较一下看哈希处的对象是否和要查找的对象相同;如果不相同,那么返回null。如果相同,则返回该哈希处的对象。
hashCode()返回一个int类型,两个int类型比较起来要快很多。
hashCode()被设计用来使得哈希容器能高效的工作。也只有在哈希容器中,才使用hashCode()来比较对象是否相等,但要注意这种比较是一种弱的比较,还要利用equals()方法最终确认。
4.需注意的地方
在自定义一个类的时候,我们必须要同时重写equals()和hashCode(),并且必须保证:
其一:如果两个对象的equals()相等,那么他们的hashCode()必定相等。
其二:如果两个对象的hashCode()不相等,那么他们的equals()必定不等。
import java.util.HashMap;
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (age != person.age) return false;
return name != null ? name.equals(person.name) : person.name == null;
}
// @Override
// public int hashCode() {
// int result = name != null ? name.hashCode() : 0;
// result = 31 * result + age;
// return result;
// }
}
public class Demo {
public static void main(String[] args) throws Exception{
Person person=new Person("xiaoming",18);
HashMap<Person,Integer> hashMap=new HashMap<Person,Integer>();
hashMap.put(person, 1);
System.out.println(hashMap.get(new Person("xiaoming",18)));
}
}
上面的代码注释掉hashCode()前后的运行结果不同,当注释掉hashCode()的时候,person和后来新建的Person虽然equals是同一对象,但HashMap容器内部在首先比较hashCode()的时候会认为他们是不同元素,所以返回的值不同。
5.面试题
两个对象的 hashCode() 相同,则 equals() 也一定为 true?
解答:不对,两个对象的 hashCode() 相同,equals() 不一定 true
代码示例:
String str1 = "通话";
String str2 = "重地";
System. out. println(String. format("str1:%d | str2:%d", str1. hashCode(),str2. hashCode()));
System. out. println(str1. equals(str2));
执行的结果:
str1:1179395 | str2:1179395
false
代码解读:很显然“通话”和“重地”的 hashCode() 相同,然而 equals() 则为 false,因为在散列表中,hashCode() 相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等