关于hashcode 和 equals 的内容总结
第一:equals() 的作用是 表示其他对象是否“等于”这个对象。
在Object源码里面 equals的作用等价于 == 即 用来比较俩个对象的内存地址是否相同
public boolean equals(Object obj) {
return (this == obj);
}
但是一般我们是想用equals来表示 俩个对象的内容是否相同的 所以需要我们去覆盖 equals的方法
以String类 的 equals方法为例 用来比较两个对象的内容是否相同
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
如果自定义的对象在没有重写equals方法的前提下 使用 equals 的话 那么执行的是 == 即比较俩个对象的内存地址是否相同
在重写equals方法的原则 (现在的IDE 基本都可以自动重写 equals方法了 要是没有特殊的需求 可以直接调用 就能使用了 熊重写equals方法的时候 还需要重写 hashcode )
1. 对称性:如果x.equals(y)返回是"true",那么y.equals(x)也应该返回是"true"。
2. 反射性:x.equals(x)必须返回是"true"。
3. 类推性:如果x.equals(y)返回是"true",而且y.equals(z)返回是"true",那么z.equals(x)也应该返回是"true"。
4. 一致性:如果x.equals(y)返回是"true",只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是"true"。
5. 非空性,x.equals(null),永远返回是"false";x.equals(和x不同类型的对象)永远返回是"false"。
第二:hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
关于hashcode 在数据结构的 查找中 有介绍 它的作用是为了 方便查找 查找的时间理论上是0(1) 在一个对象集合中(hashmap hashset ..) 你可以根据一个对象的哈希码 在哈希表上 迅速的找到它所对应的值
那么hashcode 和 equals 有什么联系呢?
为什么在重写equals的时候 一般都是要重写hashcode呢?
其实吧 说有关系也有关系 说没有关系也没有关系
第一: 如果你的这个类是 单单的用来做比较俩者的内容 并不把它们存放到 集合当中(hashmap, hashset。。。。)当中的话 他们是没有任何关系的
第二: 如果你要是把他们存放到 集合当中hashmap, hashset。。。。) 那他们就很有关系了
为什么 ? 这是因为hashcode的设计的目的 决定的 hashcode的 目的 就是为了 在集合中对对象进行查找
hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值 详细了解请 参考 public int hashCode()返回该对象的哈希码值。支持此方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。
如何要是不理解的话 可以去 看一下 哈希表的作用 哈希表你可以想象为一个数组 那么哈希码就是 数组的坐标 坐标里面的值就时 对象 然后通过哈希吗来访问响应的对象 这样的方式大大的加快了访问速率
由于哈希码生成算法的不同 难免会发生冲突 即内容不同的对象 生成的哈希吗却相同 关于处理冲突的方式 有很多种 这里 这说一种 链地址法
java的 集合(hashmap hashset 采用的就是类似于这样的方法 )
说到这里应该差不多知道 hashcode和 equals的关系了吧 即通过hashcode 定位到 具体的位置 然后通过 equals比较 这个位置的对象的内容是否和原来的相同
从而生成 各种集合操作 如
hashmap中的 get 操作 看源码
public V get(Object key) { if (key == null) return getForNullKey(); // 获取key的hash值 int hash = hash(key.hashCode()); // 在“该hash值对应的链表”上查找“键值等于key”的元素 for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null; }
put操作 put() 的作用是对外提供接口,让HashMap对象可以通过put()将“key-value”添加到HashMap中。
public V put(K key, V value) { // 若“key为null”,则将该键值对添加到table[0]中。 if (key == null) return putForNullKey(value); // 若“key不为null”,则计算该key的哈希值,然后将其添加到该哈希值对应的链表中。 int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; // 若“该key”对应的键值对已经存在,则用新的value取代旧的value。然后退出! if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } // 若“该key”对应的键值对不存在,则将“key-value”添加到table中 modCount++; addEntry(hash, key, value, i); return null; }
都是 hashcode和equals 的 合并操作
注意 : hashcode的 重写 要使得对象生成的hashcode尽量避免冲突(即重复)
另外 一般
1)、如果两个对象相等,那么它们的hashCode()值一定相同。
这里的相等是指,通过equals()比较两个对象时返回true。
2)、如果两个对象hashCode()相等,它们并不一定相等。
因为在散列表中,hashCode()相等,即两个键值对的哈希值相等。然而哈希值相等,并不一定能得出键值对相等。
==================================================================================
补充学习 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; }
最有意思的是 Integer类型的 hashcode的值 就是 内容的值
/** * Compares this object to the specified object. The result is * {@code true} if and only if the argument is not * {@code null} and is an {@code Integer} object that * contains the same {@code int} value as this object. * * @param obj the object to compare with. * @return {@code true} if the objects are the same; * {@code false} otherwise. */ public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; } /** * 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; }