java中hashcode深入浅出(equals 与hashcode)
hash算法概念
Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入通过散列算法变换成固定长度的,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
hash特点
- 相同的输入,通过相同hash函数,计数出的hash值一定相同
- 不同的输入,通过相同hash函数,计算出的hash值可能相同
- 相同hash函数计算的hash值相同,输入可能不同
- 相同hash函数计算的hash值不同,输入肯定不同
hash算法使用场景
使用场景的思想:输入与存储位置建立对应关系;便于查找
- java中的hash集合,如HashTable、HashMap、HashSet等
- 分布式中消息路由等
- 数据库分库分表等
java中hashcode
Object规范[javaSE6]:
- 在应用程序的执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对这同一个对象调用多次,hashcode方法都必须始终如一的返回同一个整数。在同一个应用程序的多次执行过程中,每次执行所返回的整数可以不一致。
- 如果两个对象根据equals(Object)方法比较是相等的,那么调用这两个对象中任意一个对象的hashcode方法都必须产生同样的整数结果。
- 如果两个对象根据equals(Object)方法比较是不相等的,那么调用这两个对象中任意一个对象的hashcode方法,则不一定要产生不同的整数结果。但是程序员应该知道,给不相等的对象产生截然不同的整数结果,有可能提高散列表(hash table)的性能。
补充说明:
- hashcode作为对象的一个压缩标记(如身份证前6位确定身份区域);因此,hashcode不能确定一个对象
- hashcode作为对象之间比较条件的一个门槛;先比较hashcode,再比较equals(身份证前6位不同,肯定不是一个区域)
- 一个好的hash函数,通常倾向于“为不相等的对象产生不相等的hashcode”。
源码hashcode分析
Object hascode()
public native int hashCode();
它是一个本地方法,可以看为返回对象地址(实际上不是)
Integer hashcode()
public static int hashCode(int value) {
return value;
}
Integer hashcode()
public static int hashCode(boolean value) {
return value ? 1231 : 1237;
}
Character hashcode()
public static int hashCode(char value) {
return (int)value;
}
String hashcode()
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];
}
hash = h;
}
return h;
}
通过以上源码可以观察出:基本类型对应的包装类的hashcode其实就是自身的值,String的hashcode是通过其中的每个char计数出来。
hashcode在hash表中使用
思想:将key与Value建立映射关系;通过key的hashcode快速找到对应的Value
hash表对象判断是否相等:首先判断hash值是否相等,然后再判断本身是否相等
if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
euqals与hashcode关系
覆盖对象的equals方法也必须覆盖hashcode方法(否则无法结合散列集合一起工作,如上hashcode在hash表中使用)
- equals相同,hashcode一定相同(对应hash特征第一条)
- equals不同,hashcode可能相同(对应hash算法概念中粗体字)