hashCode的作用及与equals的关系
要了解hashcode,首先了解下哈希表,这对我们加深理解Java中的hashcode作用有很大帮助。
数据结构中的哈希表,它可以提供快速的查找及插入,它与线性查找的区别在于,他没有具体的依赖顺序,而是通过关键字直接可以定位到存储位置
存储位置=f(关键字),简化就是:存储位置=f(key)。
这种存储技术叫做散列技术,散列技术是在记录存储位置与它的关键字之间建立确定一种对应关系f,使每个关键字对应一个f(key)存储位置。查找时,根据这个确定的对应关系可以通过key找到f(key)映射,若查找的表存在该记录,则必定是在f(key)位置上。
这种关系f我们称为散列函数,又称哈希函数,而采用散列技术将记录存储到一块连续的空间中,这段连续存储空间称为散列表,又称哈希表,那么关键字对应的记录位置我们称为散列地址。
如图可以加深理解Hash:
总结下Hash的关键结论:
1.如果散列表存在与原始输入k相等的记录,那么k肯定在f(key)的位置上;
2.不同关键字通过散列算法得出相同的值,这种现象成为哈希碰撞;
3.如果两个哈希值不同(使用同一散列算法),那么原始的输入肯定不同
那么HashCode的就是提高查找效率,用来快速确定查找原始记录的存储地址;
equals方法与hashcode的关系:
1.如果两个对象equals相等,这两个对象的hashcode一定相等,
2.如果两个对象hashcode相等,这两个对象未必相等,只能说这两个对象存储在一个地址上,(这称作hash碰撞)
3.如果对象的equals被重写,那么对象的hashcode方法也要被重写
为什么重写equals方法的时候要重写hashcode方法?
大家都知道Object类是所有类的*父类或父类,我们定义的类默认都是继承Object类,如果我们没有重写Object的equals方法和hashcode()方法,默认都是使用Object的hashcode方法:
public native int hashCode();
hashCode是个本地方法,获取的是存储地址。
再看equals方法:
public boolean equals(Object obj) {
return (this == obj);
}
equals比较的是对象相等。
这里说下equals与==的区别:
==是运算符,1.基本数据类型的值比较,2.如果是引用类型,则比较的是引用类型的地址
equals是方法,针对不同类型equals所表达的涵义不一样
如果我们改写了equals方法,没有改写hashcode方法会出现什么问题呢?
下面来个例子:
public class HashCodeTest {
private String name;
public HashCodeTest(String name) {
this.name = name;
}
public boolean equals(HashCodeTest code) {
if (this.name.equals(code.name)) {
return true;
}
return false;
}
public static void main(String[] args) {
HashCodeTest code1 = new HashCodeTest("jing");
HashCodeTest code2 = new HashCodeTest("jing");
System.out.println(code1.equals(code2));
System.out.println(code1.hashCode());
System.out.println(code2.hashCode());
}
}
打印结果:
true
366712642
1829164700
可以看到这两个对象判断相等为true,但hash值是不同的,这就有问题了,这与我们上面总结的两对象equals相等,则hash值相同矛盾,所以这个时候我们就需要重写hashcode方法。
示例JDK重写hashcode的类,以下源码基于JDK7版本,JDK8跟JDK7还是有变动的:
Integer
public int hashCode() {
return value;
}
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
String
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
HashMap
public final int hashCode() {
return (key==null ? 0 : key.hashCode()) ^
(value==null ? 0 : value.hashCode());
}
public final boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry)o;
Object k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
Object v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
}
参考资料:
http://www.cnblogs.com/xrq730/p/4842028.html
http://www.cnblogs.com/lchzls/p/6714079.html
上一篇: 如何使用JWT做简单的登录操作
下一篇: 为什么HashMap线程不安全
推荐阅读
-
hashCode的作用及与equals的关系
-
HashMap存储原理以及与hashcode、equals方法的关系
-
HashMap存储原理以及与hashcode、equals方法的关系
-
(转)hashCode与equals的区别与联系 博客分类: java
-
页面的缓存与不缓存设置及html页面中meta的作用
-
页面的缓存与不缓存设置及html页面中meta的作用
-
Java中比较运算符compareTo()、equals()与==的区别及应用总结
-
Java中==运算符与equals方法的区别及intern方法详解
-
Java中==运算符与equals方法的区别及intern方法详解
-
Java中比较运算符compareTo()、equals()与==的区别及应用总结