自定义类型作为HashMap或HashTable的key需要注意哪些问题
来源:互联网 发布:胡安巴尔加斯数据 编辑:程序博客网 时间:2024/06/05 19:59
1。覆盖equals时总要覆盖hashCode
在覆盖了equals方法的类中,也必须覆盖hashCode方法。如果不这样做的话,就会违背Object.hashCode的通用约定,从而导致该类无法结合所有基于散列的集合一起正常运行,这样的集合包括HashMap,HashSet和HashTable。
以下是Object对象API关于equal方法和hashCode方法的说明:
1。If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
2。It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the 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.
以上API说明是对之前2点的官方详细说明
关于第一点,相等(相同)的对象必须具有相等的哈希码(或者散列码),为什么?
想象一下,假如两个Java对象A和B,A和B相等(eqauls结果为true),但A和B的哈希码不同,则A和B存入HashMap时的哈希码计算得到的HashMap内部数组位置索引可能不同,那么A和B很有可能允许同时存入HashMap,显然相等/相同的元素是不允许同时存入HashMap,HashMap不允许存放重复元素。
关于第二点,两个对象的hashCode相同,它们并不一定相同
也就是说,不同对象的hashCode可能相同;假如两个Java对象A和B,A和B不相等(eqauls结果为false),但A和B的哈希码相等,将A和B都存入HashMap时会发生哈希冲突,也就是A和B存放在HashMap内部数组的位置索引相同这时HashMap会在该位置建立一个链接表,将A和B串起来放在该位置,显然,该情况不违反HashMap的使用原则,是允许的。当然,哈希冲突越少越好,尽量采用好的哈希算法以避免哈希冲突。
Hashset是继承Set接口,Set接口又实现Collection接口,这是层次关系。那么Hashset、Hashmap、Hashtable中的存储操作是根据什么原理来存取对象的呢?
下面以HashSet为例进行分析,我们都知道:在hashset中不允许出现重复对象,元素的位置也是不确定的。在hashset中又是怎样判定元素是否重复的呢?在java的集合中,判断两个对象是否相等的规则是:
1.判断两个对象的hashCode是否相等, 如果不相等,认为两个对象也不相等,完毕
如果相等,转入2(这一点只是为了提高存储效率而要求的,其实理论上没有也可以,但如果没有,实际使用时效率会大大降低,所以我们这里将其做为必需的。)
2.判断两个对象用equals运算是否相等,如果不相等,认为两个对象也不相等;如果相等,认为两个对象相等(equals()是判断两个对象是否相等的关键)
为什么是两条准则,难道用第一条不行吗?不行,因为前面已经说了,hashcode()相等时,equals()方法也可能不等,所以必须用第2条准则进行限制,才能保证加入的为非重复元素。
import java.util.HashSet;import java.util.Iterator;import java.util.Set;class Person { String id; String name; public Person(String id, String name) { this.id = id; this.name = name; } public String toString() { return "id = " + id + " , name = " + name; }}class Student { String id; String name; public Student(String id, String name) { this.id = id; this.name = name; } public int hashCode() { return id.hashCode(); } public boolean equals(Object ob) { Student student = (Student)ob; if(student.id.equals(this.id)) { return true; }else { return false; } } public String toString() { return "id = " + id + " , name = " + name; }}public class HashCodeTest { public static void main(String[] args) { testStringHash(); testHashSetWithoutEquals(); testHashSetWithEquals(); } //测试没有实现equals和hashCode public static void testHashSetWithoutEquals() { Set<Person> personSet = new HashSet<Person>(); personSet.add(new Person("123", "Tom")); personSet.add(new Person("123", "Tom")); Iterator<Person> iterator = personSet.iterator(); while(iterator.hasNext()) { Person person = iterator.next(); System.out.println(person.toString()); } } //测试实现了equals和hashCode public static void testHashSetWithEquals() { Set<Student> studentSet = new HashSet<Student>(); studentSet.add(new Student("123", "Tom")); studentSet.add(new Student("123", "Tom")); Iterator<Student> iterator = studentSet.iterator(); System.out.println("********************"); while(iterator.hasNext()) { Student student = iterator.next(); System.out.println(student.toString()); } } //String类覆盖了equals和hashCode参考jdk实现 public static void testStringHash() { Object a = new Object(); String s1 = new String("abc"); String s2 = new String("abc"); System.out.println(s1 == s2); System.out.println(s1.equals(s2)); System.out.println("hashCode s1 = " + s1.hashCode()); System.out.println("hashCode s2 = " + s2.hashCode()); Set hashSet = new HashSet<String>(); hashSet.add(s1); hashSet.add(s2); Iterator it = hashSet.iterator(); while(it.hasNext()) { System.out.println(it.next()); } System.out.println("*******************"); }}
同理hashMap的测试如下
import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Map.Entry;class Person { String id; String name; public Person(String id, String name) { this.id = id; this.name = name; } public String toString() { return "id = " + id + " , name = " + name; }}class Student { String id; String name; public Student(String id, String name) { this.id = id; this.name = name; } public int hashCode() { return id.hashCode(); } public boolean equals(Object ob) { Student student = (Student)ob; if(student.id.equals(this.id)) { return true; }else { return false; } } public String toString() { return "id = " + id + " , name = " + name; }}public class HashMapTest { public static void main(String[] args) { testHashMapWithoutEquals(); testHashMapWithEquals(); } public static void testHashMapWithoutEquals() { Map<Person, String> hMap = new HashMap<Person, String>(); Person person1 = new Person("123", "Tom"); Person person2 = new Person("123", "Tom"); hMap.put(person1, "address"); hMap.put(person2, "address"); Iterator iterator = hMap.entrySet().iterator(); while(iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); Person key = (Person) entry.getKey(); String val = (String) entry.getValue(); System.out.println("key = " + key + " value = " + val); } } public static void testHashMapWithEquals() { System.out.println("*********************"); Map<Student, String> hMap = new HashMap<Student, String>(); Student student1 = new Student("123", "Tom"); Student student2 = new Student("123", "Tom"); hMap.put(student1, "address"); hMap.put(student2, "address"); Iterator iterator = hMap.entrySet().iterator(); while(iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); Student key = (Student) entry.getKey(); String val = (String) entry.getValue(); System.out.println("key = " + key + " value = " + val); } }}
参考博客:Java提高篇——equals()与hashCode()方法详解
- 自定义类型作为HashMap或HashTable的key需要注意哪些问题
- Java用自定义的类型作为HashMap的key
- 自己创建类作为HashMap或者HashTable的键值或者Value值时需要注意点
- Java 自定义类作为HashMap的key
- Java 将自定义的对象作为HashMap的key
- Java用自定义的类作为HashMap的key值
- 自定义枚举类 Enum 是否可以作为 HashMap 的key
- java HashMap用自定义类作为key
- java HashMap用自定义类作为key
- 使用用户自定义类型作为std::map的key
- java用自定义类型作为HashMap的键
- Java 用自定义类型作为HashMap的键
- 关于set或map的key使用自定义类型的问题
- linux自定义信号需要注意的问题
- 自定义View需要注意的问题
- 自定义View需要注意的问题
- hibernate的Dao作为单例时需要注意的问题
- J2ME写好的应用程序打包,需要注意哪些问题?
- mysql 多表关联update修改操作
- Sprinmvc 简单测试Demo(二)
- 数据结构-栈
- 洛谷p3768 简单的数学题
- FreeRtos 内核函数 cmsis_os函数一览
- 自定义类型作为HashMap或HashTable的key需要注意哪些问题
- 30分钟,让你彻底明白Promise原理
- Uva207 PGA Tour Prize Money
- 保留字,变量——JavaScript知识小结03
- HTML网页的基础知识(标准流)
- spark常用函数:transformation和action
- Servlet总结
- 总结的一些Java公用函数库
- 数据结构与算法分析 C++ 查找等长单词且只有一个元素不同的所有单词