hashmap是有序还是无序_使用HashMap为什么要重写hashCode和equals

Hash算法

在说HashMap之前先来了解一下Hash算法。在数据结构中学习过线性表,我们知道在线性表中查询一个值最坏的情况可能是从头遍历到尾,其平均时间复杂度为O(n),并不理想,而hash表能将查询的时间复杂度降为O(1),因为Hash算法会通过hash函数计算出地址直接取值,其查询次数只有一次。

通过下面例子简单了解一下hash表的查询方式,下面是一个hash表,首先假设hash函数为n%10,hash函数计算出来的结果就是其hash表中该元素的地址,所以10、13和26的存储结果如下图。

b22e10f53669803adc708e6ce4c83efc.png

可能实际的hash函数能很好地避免地址的冲突,但是还是有地址冲突的可能性,比如10和20。java中hashMap解决方式是"链地址法",如下图,将hash值冲突的值使用链表连接起来,这样查询到地址0的时候就会依次比较10和20,看到底哪个才是要找的。

9e4ca63c015ee3b0fb32831fd7ff6e44.png

HashMap

下面来了解什么是HashMap,"**Map集合即Key-Value的集合,前面加个Hash,即散列,无序的。所以HashMap即散着的,无序的Key-Value集合**",这是最初我看到的一个对我个人而言比较好理解的解释。当我们使用的hashMap的键值为对象的时候可能就要重写hashCode和eqals。

先看下面一段代码

public class User {private String name;private String password;public User() {super();}public User(String name, String passed) {super();this.name = name;this.passed = passed;}public class Demo {public static void main(String[] args) {User user1=new User("name", "passed");User user2=new User("name", "passed");//定义hashMapHashMap hashmap=new HashMap();//添加hashmap.put(user1, "value1");//通过user2获取添加的valueString str=hashmap.get(user2);System.out.println("输出结果:"+str);}}

通过代码可知,实体类User中只有两个属性name和password,Main函数中声明了两个User的实例,他们的两个属性都是相同的,那我们现在希望使用user2取出user1对应的value值,看下是否能成功。

运行结果:

输出结果:null

为什么不是想象的结果呢。因为当我们向hashmap添加user1时,hashmap首先会调用User的hashCode来计算hash值作为地址,因为本例中没有重写hashCode方法,所以hashmap是调用的Object的hashCode方法来计算hash值,Object中hashCode计算出来的hash值其实就是对象的地址,所以user1与user2存储的的地址肯定不同,下面就重写User的hashCode

@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((name == null) ? 0 : name.hashCode());result = prime * result + ((passed == null) ? 0 : passed.hashCode());return result;}

运行结果:

输出结果:null

运行结果还是null,既然重写了hashCode方法,寻找user2时候理论上是能够正确寻找到user1存储地址的,为什么结果还是null?这里就要了解一下HashMap找到地址后动作。前面已经说过,java中HashMap解决hash值冲突,使用了链地址法,也就是在通过user2获取user1的value的时候并不是通过User重写的hashCode计算出user2的地址后就直接从该地址中取相应的值,而是还要调用equals方法来进行比较,这就和没有重写hashCode造成错误的原因类似了,没有重写equals方法,就要被迫调用Object类的equals方法,而Object类的equals方法是直接比较两个对象的内存地址,所以输出结果是null。

现在重写equals方法

@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;User other = (User) obj;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;if (passed == null) {if (other.passed != null)return false;} else if (!passed.equals(other.passed))return false;return true;}

运行结果:

输出结果:value1

成功。

总结

由上面的分析可知,当键值为对象类型的时候就需要重写hashCode和equals方法。

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
©️2021 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值