java中重写equals()方法的时候为什么要重写hashCode()方法?

2022-10-23 14:26:51

目录

一:什么是hashCode(),equals()方法?

二:hashCode(),equals()两种方法是什么关系?

三:为什么在重写equals方法的时候要重写hashcode的方法?

四:怎么重写这两种方法?


一:什么是hashCode(),equals()方法?

equals()在java.lang.Object下,其源码为:

/**
     * 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
     */

指示其他对象是否与此对象“相等”。equals方法实现了一个非空对象的等级方法的比较

规则

1.任何一个非空引用值与其自身比较都应该相等       {@code x.equals(x)} true

2.具有对称性   如果 x.equals(y)   true   -->y.equals(x)   也为true

3.可传递性 : 如果 x.equals(y)   true   y.equals(z)  true     -->x.equals(z) 也为 true

4.一致性:     任何一个非空的引用x y 大量的调用结果应该是一直不变的

5.对于任何一个非空的引用与null进行比较都应该为false

只有引用指向同一个对象的时候 ({@code x == y} has the value {@code true}).

请注意,一旦覆盖此方法,通常需要覆盖{@code hashCode} 方法,以便维护{@code hashCode}方法的常规协定,该方法声明相等的对象必须具有相等的哈希码。
   public boolean equals(Object obj) {
        return (this == obj);
    }

hashCode方法

  /**
     * 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&trade; programming language.)
     *
     * @return  a hash code value for this object.
     * @see     java.lang.Object#equals(java.lang.Object)
     * @see     java.lang.System#identityHashCode
     */

返回对象的哈希码值。支持此方法是为了哈希表的好处,例如 {@link java.util.HashMap}提供的哈希表。

只要在执行Java应用程序期间多次在同一对象上调用它,{@ code hashCode}方法*必须始终返回相同的整数,前提是在对象被修改了{@code equals}比较中没有提供任何信息。 从应用程序的一次执行到同一应用程序的另一次执行,此整数不需要保持一致。

如果两个对象根据{@code equals(Object)} 方法相等,则对两个对象中的每个对象调用{@code hashCode}方法必须生成相同的整数结果。

根据{@link java.lang.Object#equals(java.lang.Object)} 方法,如果两个对象不相等,然后调用{@code hashCode}每个*两个对象的方法必须产生不同的整数结果,这不是必要的。但是,程序员应该知道为不等对象生成不同的整数结果可以提高哈希表的性能。

尽管合理实用,但* class {@code Object}定义的hashCode方法确实为不同的*对象返回不同的整数。 (这通常通过将对象的内部地址转换为整数来实现,但*Java&trade;编程语言不需要此实现技术。)

  public native int hashCode();

关于equals()方法,经常说的就是比较的是内容(与==比较的地址相对),这么说不完全对--看下面这段代码:

学生类:

 public class Student {
	private int id;
	private String name;
        public Student(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
}
   public class Test {
      public static void main(String[] args) {
        Student s1=new Student(001,"邵小二");
        Student s2=new Student(001,"邵小二");
        System.out.println(s1.equals(s2));
    }
}

我们想通过一个学生的学号以及姓名来判断是否是同一个学生。可是 根据程序的运行结果(打印出的为false)来看,即使是学号与姓名两个字段都完全的相同,判断出的学生也不是相同的。

   public boolean equals(Object obj) {
        return (this == obj);
    }


即在Object中equals方法只是判断的为是否为同一个对象的引用。

在String类中,我们可以这样写,打印的结果为true。

             String str1="123";
             String str2="123";
             //print true
             System.out.println(str1.equals(str2));

 什么是hashcode方法?

在java中,对对象的存储采取了存储在哈希表中处理方法,hashcode方法是根据对象的地址转换之后返回的一个哈希值,其详细的用法在这篇文章涉及的时候详细的介绍过-点击打开链接

二:hashCode(),equals()两种方法是什么关系?

要弄清楚这两种方法的关系,就需要对哈希表有一个基本的认识。其基本的结构如下:

对于hashcode方法,会返回一个哈希值,哈希值对数组的长度取余后会确定一个存储的下标位置,如图中用数组括起来的第一列。

不同的哈希值取余之后的结果可能是相同的,这时候就用equals方法判断是否为相同的对象,不同则在链表中插入。

则有:

hashcode不相同,用equals()方法判断的返回的一定为false。

hashcode相同,equals()方法返回值不能确认,可能为true,可能为false。

三:为什么在重写equals方法的时候要重写hashcode的方法?

   上述了两种方法的关系之后,我们知道判断的时候先根据hashcode进行的判断,相同的情况下再根据equals()方法进行判断。如果只重写了equals方法,而不重写hashcode的方法,会造成hashcode的值不同,而equals()方法判断出来的结果为true。

   在Java中的一些容器中,不允许有两个完全相同的对象,插入的时候,如果判断相同则会进行覆盖。

这时候如果只重写了equals()的方法,而不重写hashcode的方法,Object中hashcode是根据对象的存储地址转换而形成的一个哈希值。这时候就有可能因为没有重写hashcode方法,造成相同的对象散列到不同的位置而造成对象的不能覆盖的问题。

四:怎么重写这两种方法?

        public class SimpleDemo {
	// 部门
	private String department;
	// 工号
	private int id;
 
	public SimpleDemo(int id, String department) {
		super();
		this.id = id;
		this.department = department;
	}
 
	public int getId() {
		return id;
	}
 
	public void setId(int id) {
		this.id = id;
	}
 
	public String getdepartment() {
		return department;
	}
 
	public void setdepartment(String department) {
		this.department = department;
	}
 
	@Override
	public int hashCode() {
		int hash = 1;
		hash = hash * 17 + id;
		hash = hash * 31 + department.hashCode();
		return hash;
	}
       @Override
	public boolean equals(Object obj) {
		if (obj == null)
			return false;
		if (obj == this)
			return true;
		if (obj instanceof SimpleDemo) {
			SimpleDemo sd = (SimpleDemo) obj;
			return sd.department.equals(department) && sd.id == id;
		}
		return false;
	}

1.给int变量赋值

2.为对象中每个有意义的字段计算出一个散列码
3.合并
4.返回结果
5.验证结果,确保相同的对象有相同的散列码

测试

     public class Test02 {
	  public static void main(String[] args) {
		SimpleDemo sdo1=new SimpleDemo(0106,"技术部");
		SimpleDemo sdo2=new SimpleDemo(0106,"技术部");
                //print true
               System.out.println(sdo1.equals(sdo2));
	}
}

String 类的方法equals方法的重写

 private final char value[];
 private int hash; //default 0
    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;
    }
    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;
    }
  • 作者:奇点_97
  • 原文链接:https://blog.csdn.net/qq_29235677/article/details/90238099
    更新时间:2022-10-23 14:26:51