在上一篇博文 Java 中 equals 和 == 的区别中介绍了 Object 类的 equals 方法, 并且也介绍了我们可在重写 equals 方法, 本章我们来说一下为什么重写 equals 方法的时候也要重写 hashCode 方法.
先让我们来看看 Object 类源码
- /**
- * Returns a hash code value for the object. This method is
- * supported for the benefit of hash tables such as those provided by
- * {@link java.util.HashMap}.
- * <p>
- * The general contract of {@code hashCode} is:
- * <ul>
- * <li>Whenever it is invoked on the same object more than once during
- * an execution of a Java application, the {@code hashCode} method
- * must consistently return the same integer, provided no information
- * used in {@code equals} comparisons on the object is modified.
- * This integer need not remain consistent from one execution of an
- * application to another execution of the same application.
- * <li>If two objects are equal according to the {@code equals(Object)}
- * method, then calling the {@code hashCode} method on each of
- * the two objects must produce the same integer result.
- * <li>It is <em>not</em> required that if two objects are unequal
- * according to the {@link java.lang.Object#equals(java.lang.Object)}
- * method, then calling the {@code hashCode} method on each of the
- * two objects must produce distinct integer results. However, the
- * programmer should be aware that producing distinct integer results
- * for unequal objects may improve the performance of hash tables.
- * </ul>
- * <p>
- * As much as is reasonably practical, the hashCode method defined by
- * class {@code Object} does return distinct integers for distinct
- * objects. (This is typically implemented by converting the internal
- * address of the object into an integer, but this implementation
- * technique is not required by the
- * Java™ programming language.)
- *
- * @return a hash code value for this object.
- * @see java.lang.Object#equals(java.lang.Object)
- * @see java.lang.System#identityHashCode
- */
- public native int hashCode();
- /**
- * Indicates whether some other object is "equal to" this one.
- * <p>
- * The {@code equals} method implements an equivalence relation
- * on non-null object references:
- * <ul>
- * <li>It is <i>reflexive</i>: for any non-null reference value
- * {@code x}, {@code x.equals(x)} should return
- * {@code true}.
- * <li>It is <i>symmetric</i>: for any non-null reference values
- * {@code x} and {@code y}, {@code x.equals(y)}
- * should return {@code true} if and only if
- * {@code y.equals(x)} returns {@code true}.
- * <li>It is <i>transitive</i>: for any non-null reference values
- * {@code x}, {@code y}, and {@code z}, if
- * {@code x.equals(y)} returns {@code true} and
- * {@code y.equals(z)} returns {@code true}, then
- * {@code x.equals(z)} should return {@code true}.
- * <li>It is <i>consistent</i>: for any non-null reference values
- * {@code x} and {@code y}, multiple invocations of
- * {@code x.equals(y)} consistently return {@code true}
- * or consistently return {@code false}, provided no
- * information used in {@code equals} comparisons on the
- * objects is modified.
- * <li>For any non-null reference value {@code x},
- * {@code x.equals(null)} should return {@code false}.
- * </ul>
- * <p>
- * The {@code equals} method for class {@code Object} implements
- * the most discriminating possible equivalence relation on objects;
- * that is, for any non-null reference values {@code x} and
- * {@code y}, this method returns {@code true} if and only
- * if {@code x} and {@code y} refer to the same object
- * ({@code x == y} has the value {@code true}).
- * <p>
- * Note that it is generally necessary to override the {@code hashCode}
- * method whenever this method is overridden, so as to maintain the
- * general contract for the {@code hashCode} method, which states
- * that equal objects must have equal hash codes.
- *
- * @param obj the reference object with which to compare.
- * @return {@code true} if this object is the same as the obj
- * argument; {@code false} otherwise.
- * @see #hashCode()
- * @see java.util.HashMap
- */
- public boolean equals(Object obj) {
- return (this == obj);
- }
hashCode: 是一个 native 方法, 返回的是对象的内存地址,
equals: 对于基本数据类型,== 比较的是两个变量的值. 对于引用对象,== 比较的是两个对象的地址.
接下来我们看下 hashCode 的注释
1. 在 Java 应用程序执行期间, 在对同一对象多次调用 hashCode 方法时, 必须一致地返回相同的整数, 前提是将对象进行 equals 比较时所用的信息没有被修改.
从某一应用程序的一次执行到同一应用程序的另一次执行, 该整数无需保持一致.
2. 如果根据 equals(Object) 方法, 两个对象是相等的, 那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果.
3. 如果根据 equals(java.lang.Object) 方法, 两个对象不相等, 那么两个对象不一定必须产生不同的整数结果.
但是, 程序员应该意识到, 为不相等的对象生成不同整数结果可以提高哈希表的性能.
从 hashCode 的注释中我们看到, hashCode 方法在定义时做出了一些常规协定, 即
1, 当 obj1.equals(obj2) 为 true 时, obj1.hashCode() == obj2.hashCode()
2, 当 obj1.equals(obj2) 为 false 时, obj1.hashCode() != obj2.hashCode()
hashcode 是用于散列数据的快速存取, 如利用 HashSet/HashMap/Hashtable 类来存储数据时, 都是根据存储对象的 hashcode 值来进行判断是否相同的. 如果我们将对象的 equals 方法重写而不重写 hashcode, 当我们再次 new 一个新的对象的时候, equals 方法返回的是 true, 但是 hashCode 方法返回的就不一样了, 如果需要将这些对象存储到结合中 (比如: Set,Map ...) 的时候就违背了原有集合的原则, 下面让我们通过一段代码看下.
- /**
- * @see Person
- * @param args
- */
- public static void main(String[] args)
- {
- HashMap<Person, Integer> map = new HashMap<Person, Integer>();
- Person p = new Person("jack",22,"男");
- Person p1 = new Person("jack",22,"男");
- System.out.println("p 的 hashCode:"+p.hashCode());
- System.out.println("p1 的 hashCode:"+p1.hashCode());
- System.out.println(p.equals(p1));
- System.out.println(p == p1);
- map.put(p,888);
- map.put(p1,888);
- map.forEach((key,val)->{
- System.out.println(key);
- System.out.println(val);
- });
- }
equals 和 hashCode 方法的都不重写
- public class Person
- {
- private String name;
- private int age;
- private String sex;
- Person(String name,int age,String sex){
- this.name = name;
- this.age = age;
- this.sex = sex;
- }
- }
p 的 hashCode:356573597
p1 的 hashCode:1735600054
false
false
com.blueskyli. 练习. Person@677327b6
888
com.blueskyli. 练习. Person@1540e19d
888
只重写 equals 方法
- public class Person
- {
- private String name;
- private int age;
- private String sex;
- Person(String name,int age,String sex){
- this.name = name;
- this.age = age;
- this.sex = sex;
- }
- @Override public boolean equals(Object obj)
- {
- if(obj instanceof Person){
- Person person = (Person)obj;
- return name.equals(person.name);
- }
- return super.equals(obj);
- }
- }
p 的 hashCode:356573597
p1 的 hashCode:1735600054
true
false
com.blueskyli. 练习. Person@677327b6
888
com.blueskyli. 练习. Person@1540e19d
888
equals 和 hashCode 方法都重写
- public class Person
- {
- private String name;
- private int age;
- private String sex;
- Person(String name,int age,String sex){
- this.name = name;
- this.age = age;
- this.sex = sex;
- }
- @Override public boolean equals(Object obj)
- {
- if(obj instanceof Person){
- Person person = (Person)obj;
- return name.equals(person.name);
- }
- return super.equals(obj);
- }
- @Override public int hashCode()
- {
- return name.hashCode();
- }
- }
p 的 hashCode:3254239
p1 的 hashCode:3254239
true
false
com.blueskyli. 练习. Person@31a7df
888
我们知道 map 是不允许存在相同的 key 的, 由上面的代码可以知道, 如果不重写 equals 和 hashCode 方法的话会使得你在使用 map 的时候出现与预期不一样的结果, 具体 equals 和 hashCode 如何重写, 里面的逻辑如何实现需要根据现实当中的业务来规定.
总结:
1, 两个对象, 用 == 比较比较的是地址, 需采用 equals 方法 (可根据需求重写) 比较.
2, 重写 equals()方法就重写 hashCode()方法.
3, 一般相等的对象都规定有相同的 hashCode.
4,String 类重写了 equals 和 hashCode 方法, 比较的是值.
5, 重写 hashcode 方法为了将数据存入 HashSet/HashMap/Hashtable(可以参考源码有助于理解)类时进行比较
来源: https://www.cnblogs.com/blueskyli/p/9936076.html