正好上次我们学习了equals方法,这次我们继续讨论它,不过不是跟==了,而是和hashCode方法作比较,关于hashCode那可是一个重要角色,在以后的学习中也会多次探讨这个方法,这次我们就简单的从equals()与hashCode()开始吧!
庆哥: 还记得equals()吗?
小白: 这个当然记得啊,上次我们不是刚讨论过嘛。
庆哥:
那好,你给我说说==和equals的区别吧!
小白:
没问题,我就说说,正好检验下我之前学的如何,对于他们的区别,我们一般比较的都是引用数据类型,因为基础数据类型都是使用“==”的,因为equals是一个方法。
对于引用数据类型,如果使用==的话,那比较的就是两个对象的内存地址,如果使用equals的话则是比较两个对象的内容,也就是内存地址所指向的内容。
庆哥:
说的很不错,看来我们之前的讨论不是白费功夫啊。下面我再总结一下!
我们知道equals是Object中的一个普通方法,如果我们没有对其进行重写的话,那么它和“==”是完全等价的,所以我们一般会对equals进行重写,使其按照我们的需求进行比较,我们常见的就是String类中的equals重写了Object中的equals方法,使其比较的是字符的内容,而不是引用地址!
小白:
那是当然,真的让我学到知识啦,今天我们还要讨论equals的知识吗?
庆哥:
是的,今天我们继续来说说equals,不过这次是和hashCode这个方法一起来说,你听说过这个hashCode吗?
小白:
听过,我之前看过一些面试题,经常会看到这个hashCod,看来这是一个重点知识啦!
庆哥:
是的,这个hashCode是一个比较重要的知识,后续我们也会继续讨论关于它的一些相关问题,今天我们就先从equals()与hashCode()开始。
小白:
![]()
这个。。关于equals我们不只是已经讨论过了吗?那是不是这次的重点就是hashCode了。
庆哥:
是的,我们这次主要讨论的就是hashCode,只不过这个hashCode有些知识是与equals相关的,所以我们就把他们放在一起来说了,把这个知识放到这次来说,也是因为之前我们已经学过equals的知识了,所以这次就不用再来说equals了,让我们可以吧重点放在hashCode上面!那你对hashCode了解多少呢?
小白:
庆哥:
看来你对hashCode不是很了解啊,那我就直接说了,首先我们最直观的来看下hashCode方法没看下面一段代码
String s1 = "hello";
System.out.println(s1.hashCode());
你知道输出结果是什么吗?
小白:
庆哥:
哈哈,其实我也不知道,因为他的结果是这样的
小白:
庆哥:
hashCode是一个方法,跟equals方法是一样的都是Object类中的方法,一个对象调用hashCode方法会得到一个hashCode值,这个值一般就是一串数字,我们之前说过,对于equals方法是要被覆盖的,不然跟==就没有什么区别了,那么这里就要记住了,当equals被覆盖的时候,hashCode也要被覆盖!
小白:
庆哥:
为什么?我不打算告诉你,因为hashCode有很多知识需要我们去研究,这里就是一个知识点,那就是为什么重写equals的时候还要重写hashCode呢?关于这个问题,我们先放在这,改天我们单独来说说这件事!
小白:
要单独拿出来说啊,看来是比较重要的知识点啊,好,那我们就改天再议,哈哈。那继续写给我说说这个hashCode吧!
庆哥:
我们通过上面的例子得到一串数字,hashCode叫做散列码,也叫作哈希码,其实就是一串数字啦,我们再看一个例子
String s1 = "hello";
String s2 = new String("hello");
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
你就判断一下这两个哈希码是否相同呢?
小白:
庆哥:
哈哈,还是看结果吧!
![]()
可以看到,结果是一样的,这是为甚呢?
小白:
庆哥:
好好,我不问,我说吧,这里就需要记住关于hashCode的几个知识点了。
- 对于字符串对象是根据字符内容得出hashCode的,因为这里s1和s2最终指向的都是“hello”,因为字符内容是一样的,所以得出的哈希码也是相同的。
- 如果两个对象通过equals比较是相同的,那么他们调用各自的hashCode方法得出的哈希码就是相同的。
这也很好理解,因为equals比较的就是内容,内容一样得出的哈希码就是一样的。那么你说两个对象调用hashCode方法得出的哈希码相同,那么这两个对象的内容是否一致呢?也就是根据equals方法比较是否一样呢?
小白:
庆哥:
淡定淡定,其实啊,如果两个对象的哈希码相同,他们则不一定相同,但是如果两个对象是一样的,那他们的hashCode则一定相同。
小白:
这个对象相等,是不是就是指的通过equals比较,他们是相等的。
庆哥: 是的,记住我们这里谈论的对象相等,都是两个对象经过equals比较,为了不让你产生混乱,你就记住我们这里都是以字符串对象为例,字符串对象的equals比较的是字符内容,不是引用地址!
小白:
嗯嗯,记住是在讨论字符串对象就不容易乱了,那这个hashCode有什么用呢?
庆哥:
![]()
接下来就是重点了,就是在面试中可能会遇到的一个问题,就是在集合中,set集合是不允许元素重复的,那么是如何保证元素不重复呢?
小白:
这个,,通过equals不是可以比较字符内容是否一样吗?
庆哥:
这个确实可以,但是当数据比较多的时候,比如说有1000个数据了,当添加1001个数据的时候就要调用1000次equals方法来比较,这样显然会大大降低效率的,那么该怎么办呢?这就要使用到hashCode了。
当添加一个新的元素的时候,首先调用这个元素的hashCode方法,然后得到一个哈希码,然后这个哈希码就作为这个元素的存储地址,如果这个哈希码制定的位置上没有元素,就直接存储在这个位置上,如果这个位置上有元素再调用equals方法比较,相同则不再存储,不相同的话就产生冲突,这时候会产生一个链接表,将这两个元素串起来放在同一个哈希码指定的位置上,而实际上会尽量避免哈希冲突!
小白:
那使用hashCode的话会极大的提升存储效率啊,因为不用每次都调用equals来进行比较了!
庆哥:
是的,所以在集合查找的时候,hashCode会降低对象比较次数,极大的提高查找效率!而实际上,一般两个对象,他们的哈希码也是不同的,当然我们上面说的字符串例子是因为字符内容一样!
小白:
![]()
庆哥能不能给总结一下!
庆哥:
equals方法和hashCode方法都是Object中的方法,在Object中equals比较的是两个对象的内存地址,而hashCode则返回这个对象的内存地址,当然一般都会对他们进行重写,而且两个是一起被重写的,我们经常见到的就是像String等这些包装类,重写equals方法来比较对象内容,重写hashCode来获得哈希码,如果通过equal比较相等的话,得到的哈希码也是相等的,一般不同的对象,hashCode也是不同的!
小白: