Java hashCode 和 equals
当向Set集合中插入对象时,如何判别在集合中是否已经存在该对象。如果采用equals方法对元素逐一进行比较,这样的做法较为耗时。可以先判断hashcode值,HashMap中用一个table保存已经存进去的对象的hashcode值,如果table中没有该hashcode值,它就可以直接存进去;如果存在该值, 就调用它的equals方法与新元素进行比较,相同则不存,不同则散列到其他位置。这样当数据量大时就减少了equals函数的调用,极大地提高了效率。
1. Equals
Object类:直接比较两个对象的地址
public boolean equals(Object obj) { return (this == obj); }
String类:比较对象的内容,Math、Integer、Double等类中的equals函数也是进行内容的比较
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = count; if (n == anotherString.count) { char v1[] = value; char v2[] = anotherString.value; int i = offset; int j = anotherString.offset; while (n– != 0) { if (v1[i++] != v2[j++]) return false; } return true; } } return false; }
2. Hashcode
hashcode对于list集合没有什么意义,但对HashMap、HashSet、HashTable的存取有重要作用。在Java中hashCode方法的主要作用是为了配合基于散列的集合一起正常运行。hashcode的计算是根据对象的属性进行散列的,过多属性参与散列会降低集合的存取效率,太少则容易发生散列冲突, 从而影响hash列表的性能。
Object类:默认情况下是根据存储地址进行映射
public native int hashCode();
String类:
public int hashCode() { int h = hash; if (h == 0) { int off = offset; char val[] = value; int len = count; for (int i = 0; i < len; i++) { h = 31 * h + val[off++]; } hash = h; } return h; }
3. hashcode和equals函数的关系:
1) 如果两个对象相同(equals比较相等),那么它们的hashCode值一定要相同。
这样就不会导致两个相同的对象因为hashCode值不一样而同时存入HashMap, 而HashMap不允许存放重复元素
2) 如果两个对象的hashCode相同,它们并不一定相同,这里的对象相同指的是用equals方法比较。
3) 在一个Java应用的执行期间,如果一个对象提供给equals做比较的信息没有被修改的话,该对象多次调用hashCode()
方法,该方法必须始终如一返回同一个整数值。
· 在重写equals方法的同时,必须重写hashCode方法
package com.sa.io; import java.util.HashMap; class People { private String name; private int age; public People(String name, int age) { this.name = name; this.age = age; } @Override public boolean equals(Object obj) { return name.equals(((People)obj).name) && age == ((People)obj).age; } } public class HashCodeTest { public static void main(String[] args) { HashMap<People, Integer> hashMap = new HashMap<People, Integer>(); hashMap.put(new People("kelly", 18), 1); System.out.println(hashMap.get(new People("kelly", 18))); // 返回值为null, 因为People只重写了equals函数没有重写hashcode函数, // 默认情况下,hashCode方法是将对象的存储地址进行映射。这里生成了两个对象,存储地址不一样,因此查找不到该对象 } }
· hashCode函数依赖的字段变化时,hashCode值也发生变化
class People { private String name; private int age; public People(String name, int age) { this.name = name; this.age = age; } public void setAge(int age) { this.age = age; } @Override public int hashCode() { return name.hashCode() * 27 + age; } @Override public boolean equals(Object obj) { return name.equals(((People)obj).name) && age == ((People)obj).age; } } public class HashCodeTest { public static void main(String[] args) { HashMap<People, Integer> hashMap = new HashMap<People, Integer>(); People people = new People("kelly", 18); hashMap.put(people, 1); people.setAge(23); System.out.println(hashMap.get(people));
// 返回值为null, 因为age是hashcode函数依赖的属性,该值发生变化后hashcode值也改变
// 如果没有重写hashcode函数,则equals返回true, 然而结果却返回1。因为get方法先用==判断对象是否相同,然后才调用equals
} }
HashMap的get方法
public V get(Object key) { if (key == null) return getForNullKey(); int hash = hash(key.hashCode()); for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) // hash -> (key) == -> equals return e.value; } return null; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix