Object类中equals方法和hashcode方法

equals():用来判断两个对象是否相同,在Object类中是通过判断对象间的内存地址来决定是否相同
hashCode():获取哈希码,也称为散列码,返回一个int整数。这个哈希码的作用是通过该对象在哈希表中的索引位置。
由于同为Object类中的方法,所以基本上所有java类都会继承这两个方法,所以通过阅读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
     */
    public native int hashCode();

概括为以下几点:
1.该方法返回对象的哈希码,支持该方法是为哈希表提供一些优点,例如,HashMap提供的哈希表
2.同一个对象未发生改变时多次调用hashCode()返回值必须相同
3.两个对象equals不相等,那么两对象的hashCode()返回必定不同
4.两个对象的hashCode()返回值相同,两对象不一定相同,还需要通过equals()再次判断。
5.当equals方法被重写时,通常有必要重写hashCode方法
通过第1点其实可以看出,hashCode()在散列表中才有用,在其他情况下没用。在散列表中hashCode()的作用是获取对象的散列码,进而确定该对象在散列表中的位置,当对象不会来创建像hashMap、HashSet等散列表时,hashCode()实际上用不上。
我们可以结合下面的代码给出更好的理解:

package packages.model0119;

import java.util.HashSet;

public class JavaHashCode {

	static class Animal {
		private String color;

		public Animal(String color) {
			this.color = color;
		}

		@Override
		public String toString() {
			return "Animal [color=" + color + "]";
		}
	}
	public static void main(String[] args) {
		HashSet set1 = new HashSet();
		set1.add("1");
		set1.add("1");
		
		for (Object a :set1) {
			System.out.println(a);
		}
		HashSet set2 = new HashSet();
		Animal a1 = new Animal("black");
		Animal a2 = new Animal("black");
		set2.add(a1);
		set2.add(a2);
		for (Object a : set2) {
			System.out.println(a);
		}
	}
}

打印输出:

1
Animal [color=black]
Animal [color=black]

由于HashSet是不可重复集合,所以输出的结果中set1和set2中都应该只有一个元素,但是为什么set2发生了重复现象?
分析原因前需要了解哈希表的底层实现,hashCode在哈希表中充当的作用:
举一个例子说明一下:
假设内存中有0 1 2 3 4 5 6 7 8这8个位置,如果我有个字段叫做ID,那么我要把这个字段存放在以上8个位置之一,如果不用HashCode而随意存放,那么当查找是就需要到8个位置汇总去挨个查找
使用HashCode则效率会快很多,把ID的HashCode%8,然后把ID存放在取得余数的那个位置,然后每次查找该类的时候都可以通过ID的HashCode%8求余数直接找到存放的位置了
如果ID的HashCode%8算出来的位置上本身已经有数据了怎么办》这就取决于算法的实现了,比如ThreadLocal中的做法就是从算出来的位置向后查找第一个为空的位置,放置数据;HashMap的做法就是通过链式结构连起来。反正,只要保证放的时候和取的时候的算法一致就行了。
如果ID的HashCode%8相等怎么办(这种对应的是第三点说的链式结构的场景)?这时候就需要定义equals了。先通过HashCode%8来判断类在哪一位置,再通过equals来在这个位置上寻找需要的类。对比两个类的时候也差不多,先通过HashCode比较,假如HashCode相等再判断equals。如果两个类的HashCode都不相同,那么这两个类必定是不同的。
其实HashSet就是采用的这种存储方式和获取方式,通过HashCode和equals组合的方式来保证集合无重复。也说明了HashCode()在散列表中是发挥作用的。
我们再来分析一下上面的代码:
set1.add(“1”);:set1集合为空,找到hashCode对应在哈希表中的存储区,直接存入字符串1
set1.add(“1”);:首先判断该字符串1的hashCode值对应哈希表中所在的存储区域是否有相同的hashCode,此处调用String类中的hashCode(),显然两次返回了相同的hashCode,接着进行equals()方法的比较,此处调用String类中的equals(),由于两个字符串指向常量池的同一个字符串1,所以两个String对象相同,字符串重复,不进行存储。
set2.add(a1);:set2结合为空,找到对象a1的hashCode对应在哈希表中的存储区,直接存入对象a1
set2.add(a2);:首先判断该对象a1的hashCode值对应哈希表中所在的存储区域是否有相同的hashCode,Animal中未重写hashCode()此处调用object类中的hashCode(),所以jdk使用默认Object的hashCode方法,返回内存地址转换后的整数,因为a1、a2为不同对象,地址值不同,所以这里不存在与a2相同的hashCode值的对象,直接存入对象a2。
所以set2重复的原因是hashCode、equals的不规范使用。
代码修改如下,重写equals和hashCode:

package packages.model0119;

import java.util.HashSet;

public class JavaHashCode {

	static class Animal {
		private String color;

		public Animal(String color) {
			this.color = color;
		}

		
		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + ((color == null) ? 0 : color.hashCode());
			return result;
		}


		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			Animal other = (Animal) obj;
			if (color == null) {
				if (other.color != null)
					return false;
			} else if (!color.equals(other.color))
				return false;
			return true;
		}


		@Override
		public String toString() {
			return "Animal [color=" + color + "]";
		}
	}
	public static void main(String[] args) {
		HashSet set1 = new HashSet();
		set1.add("1");
		set1.add("1");
		
		for (Object a :set1) {
			System.out.println(a);
		}
		HashSet set2 = new HashSet();
		Animal a1 = new Animal("black");
		Animal a2 = new Animal("black");
		set2.add(a1);
		set2.add(a2);
		for (Object a : set2) {
			System.out.println(a);
		}
	}
}

控制台打印结果:

1
Animal [color=black]

hashCode主要用于提升查询效率提高哈希表性能,来确定在散列结构中对象的存储地址
重写equals()必须重写hashCode()
哈希存储结构中,添加元素重复性校验的标准就是先检查hashCode值,后判断equals()
两个对象的equals()相等,hashCode()必定相等
两个对象的hashCode()不等,equals()必定也不等
两个对象hashCode()相等,对象不一定相等,需要通过equals()进一步判断。
参考:Java中equals()和HashCode()的关系

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

z晨晨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值