- 浏览: 278699 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (133)
- GWT (7)
- IT生活 (9)
- JAVA综合 (38)
- Servlet (5)
- vaadin (2)
- About Eclipse (2)
- StarUML (1)
- Spring (7)
- ibatis (3)
- web (35)
- ExtJs (2)
- Quartz (13)
- Struts (1)
- 学习XML (6)
- io流 (2)
- web应用之压缩 (3)
- Spring MVC (0)
- Velocity (5)
- 静态代码分析工具 (2)
- 观点 (1)
- JUnit (3)
- jQuery (4)
- mysql (2)
- javascript (16)
- linux (4)
- pattern (1)
- java加密技术 (2)
最新评论
-
tan4836128:
确实不行,我的1.8.5,降到1.6.2也不行,楼主的情况很局 ...
Spring调用Quartz定时任务报Couldn't store trigger异常 -
alfusen_xiong:
有没有自动注入的方法可以取代executeInternal() ...
Quartz任务中调用Spring容器中bean及动态调度任务 -
luoxiang183:
换了也不行啊
Spring调用Quartz定时任务报Couldn't store trigger异常 -
liubey:
首先谢谢LZ的文章,其实我想问个问题,既然有心做成工具类,就最 ...
对象和map转换 -
小林夕:
几年前用还行,现在做UML一般都开始使用在线作图工具了,可以了 ...
StarUML简介
经常在论坛上面看到覆写hashCode函数的问题,很多情况下是一些开发者不了解hash code,或者和equals一起用的时候不太清楚为啥一定要覆写hashCode。
对于hash code的理论我不想多说,这个话题太大。那些“对称性”,“传递性”的规则网上有无数的文章来描述。我只想说用hash code的原因只有一个:效率。理论的说法它的复杂度只有O(1)。试想我们把元素放在线性表里面,每次要找一个元素必须从头一个一个的找它的复杂度有O(n)。如果放在平衡二叉树,复杂度也有O(log n)。
为啥很多地方说“覆写equals的时候一定要覆写hashCode”。说到这里我知道很多人知道有个原则:如果a.equals(b)那么要确保a.hashCode()==b.hashCode()。为什么?hashCode和我写的程序的业务逻辑毫无关系,为啥我要override? 要我说如果你的class永远不可能放在hash code为基础的容器内,不必劳神,您真的不必override hashCode()
说得准确一点放在HashMap和Hashtable里面如果是作为value而不是作为key的话也是不必override hashCode了。至于HashSet,实际上它只是忽略value的HashMap,每次HashSet.add(o)其实就是HashMap.put(o, dummyObject)。
那为什么放到Hash容器里面要overide hashCode呢?因为每次get的时候HashMap既要看equals是不是true也要看hash code是不是一致,put的时候也是要看equals和hash code。
如果说到这里您还是不太明白,咱就举个例子:
譬如把一个自己定义的class Foo{...}作为key放到HashMap。实际上HashMap也是把数据存在一个数组里面,所以在put函数里面,HashMap会调Foo.hashCode()算出作为这个元素在数组里面的下标,然后把key和value封装成一个对象放到数组。等一下,万一2个对象算出来的hash code一样怎么办?会不会冲掉?先回答第2个问题,会不会冲掉就要看Foo.equals()了,如果equals()也是true那就要冲掉了。万一是false,就是所谓的collision了。当2个元素hashCode一样但是equals为false的时候,那个HashMap里面的数组的这个元素就变成了链表。也就是hash code一样的元素在一个链表里面,链表的头在那个数组里面。
回过来说get的时候,HashMap也先调key.hashCode()算出数组下标,然后看equals如果是true就是找到了,所以就涉及了equals。
假设如果有个key为a的元素在HashMap里面的情况:
1:如果这时候用equals为true但是hashCode不等的b作为get参数的话,这个时候b算出来的数组下标一定不是a所在的下标位置。
2:如果这时候用equals为false但是hashCode相等的b作为get参数的话,这个时候b算出来的数组下标是对了,但是用equals来寻找相符的key就找不到a了。
以上2种情况要么就是get找不到符合的元素返回null,要么就是返回一个hashCode和equals恰好都符合b的另外的元素,这就产生了混乱。混乱的根本就是错误实现hashCode和equals。
下面有个非常简化版的HashMap实现帮助大家理解,您甚至可以把它当作伪代码来看。(这个实现只是为了模拟HashMap的机制,所以参数检查,访问修饰符都忽略。在java.util.HashMap里面的对hash值的二次hash,根据数组长度计算index,以及超出数组时的resize都忽略)
view plaincopy to clipboardprint?01./* 02. * Just to demonstrate hash map mechanism, 03. * Please do not use it in your commercial product. 04. * 05. * Argument checking and modifier are ignored. 06. * In java.util.HashMap, array are used instead of ArrayList, so index of array is calculated by 'h & (length-1)', 07. * while we use ArrayList to skip the calculation for simple. 08. * 09. * @author Shengyuan Lu 卢声远 <michaellufhl@yahoo.com.cn> 10. */ 11.public class SimpleHashMap { 12. ArrayList<LinkedList<Entry>> entries = new ArrayList<LinkedList<Entry>>(); 13. 14. /** 15. * Each key-value is encapsulated by Entry. 16. */ 17. static class Entry { 18. Object key; 19. Object value; 20. public Entry(Object key, Object value) { 21. this.key = key; 22. this.value = value; 23. } 24. } 25. void put(Object key, Object value) { 26. LinkedList<Entry> e = entries.get(key.hashCode()); 27. if (e != null) { 28. for (Entry entry : e) { 29. if (entry.key.equals(key)) { 30. entry.value = value;// Match in lined list 31. return; 32. } 33. } 34. e.addFirst(new Entry(key, value));// Add the entry to the list 35. } else { 36. // Put the new entry in array 37. LinkedList<Entry> newEntry = new LinkedList<Entry>(); 38. newEntry.add(new Entry(key, value)); 39. entries.add(key.hashCode(), newEntry); 40. } 41. } 42. Object get(Object key) { 43. LinkedList<Entry> e = entries.get(key.hashCode()); 44. if (e != null) { 45. for (Entry entry : e) { 46. if (entry.key.equals(key)) { 47. return entry.value; 48. } 49. } 50. } 51. return null; 52. } 53. 54. /** 55. * Do we need to override equals() and hashCode() for SimpleHashMap itself? 56. * I don't know either:) 57. */ 58.}
对于hash code的理论我不想多说,这个话题太大。那些“对称性”,“传递性”的规则网上有无数的文章来描述。我只想说用hash code的原因只有一个:效率。理论的说法它的复杂度只有O(1)。试想我们把元素放在线性表里面,每次要找一个元素必须从头一个一个的找它的复杂度有O(n)。如果放在平衡二叉树,复杂度也有O(log n)。
为啥很多地方说“覆写equals的时候一定要覆写hashCode”。说到这里我知道很多人知道有个原则:如果a.equals(b)那么要确保a.hashCode()==b.hashCode()。为什么?hashCode和我写的程序的业务逻辑毫无关系,为啥我要override? 要我说如果你的class永远不可能放在hash code为基础的容器内,不必劳神,您真的不必override hashCode()
说得准确一点放在HashMap和Hashtable里面如果是作为value而不是作为key的话也是不必override hashCode了。至于HashSet,实际上它只是忽略value的HashMap,每次HashSet.add(o)其实就是HashMap.put(o, dummyObject)。
那为什么放到Hash容器里面要overide hashCode呢?因为每次get的时候HashMap既要看equals是不是true也要看hash code是不是一致,put的时候也是要看equals和hash code。
如果说到这里您还是不太明白,咱就举个例子:
譬如把一个自己定义的class Foo{...}作为key放到HashMap。实际上HashMap也是把数据存在一个数组里面,所以在put函数里面,HashMap会调Foo.hashCode()算出作为这个元素在数组里面的下标,然后把key和value封装成一个对象放到数组。等一下,万一2个对象算出来的hash code一样怎么办?会不会冲掉?先回答第2个问题,会不会冲掉就要看Foo.equals()了,如果equals()也是true那就要冲掉了。万一是false,就是所谓的collision了。当2个元素hashCode一样但是equals为false的时候,那个HashMap里面的数组的这个元素就变成了链表。也就是hash code一样的元素在一个链表里面,链表的头在那个数组里面。
回过来说get的时候,HashMap也先调key.hashCode()算出数组下标,然后看equals如果是true就是找到了,所以就涉及了equals。
假设如果有个key为a的元素在HashMap里面的情况:
1:如果这时候用equals为true但是hashCode不等的b作为get参数的话,这个时候b算出来的数组下标一定不是a所在的下标位置。
2:如果这时候用equals为false但是hashCode相等的b作为get参数的话,这个时候b算出来的数组下标是对了,但是用equals来寻找相符的key就找不到a了。
以上2种情况要么就是get找不到符合的元素返回null,要么就是返回一个hashCode和equals恰好都符合b的另外的元素,这就产生了混乱。混乱的根本就是错误实现hashCode和equals。
下面有个非常简化版的HashMap实现帮助大家理解,您甚至可以把它当作伪代码来看。(这个实现只是为了模拟HashMap的机制,所以参数检查,访问修饰符都忽略。在java.util.HashMap里面的对hash值的二次hash,根据数组长度计算index,以及超出数组时的resize都忽略)
view plaincopy to clipboardprint?01./* 02. * Just to demonstrate hash map mechanism, 03. * Please do not use it in your commercial product. 04. * 05. * Argument checking and modifier are ignored. 06. * In java.util.HashMap, array are used instead of ArrayList, so index of array is calculated by 'h & (length-1)', 07. * while we use ArrayList to skip the calculation for simple. 08. * 09. * @author Shengyuan Lu 卢声远 <michaellufhl@yahoo.com.cn> 10. */ 11.public class SimpleHashMap { 12. ArrayList<LinkedList<Entry>> entries = new ArrayList<LinkedList<Entry>>(); 13. 14. /** 15. * Each key-value is encapsulated by Entry. 16. */ 17. static class Entry { 18. Object key; 19. Object value; 20. public Entry(Object key, Object value) { 21. this.key = key; 22. this.value = value; 23. } 24. } 25. void put(Object key, Object value) { 26. LinkedList<Entry> e = entries.get(key.hashCode()); 27. if (e != null) { 28. for (Entry entry : e) { 29. if (entry.key.equals(key)) { 30. entry.value = value;// Match in lined list 31. return; 32. } 33. } 34. e.addFirst(new Entry(key, value));// Add the entry to the list 35. } else { 36. // Put the new entry in array 37. LinkedList<Entry> newEntry = new LinkedList<Entry>(); 38. newEntry.add(new Entry(key, value)); 39. entries.add(key.hashCode(), newEntry); 40. } 41. } 42. Object get(Object key) { 43. LinkedList<Entry> e = entries.get(key.hashCode()); 44. if (e != null) { 45. for (Entry entry : e) { 46. if (entry.key.equals(key)) { 47. return entry.value; 48. } 49. } 50. } 51. return null; 52. } 53. 54. /** 55. * Do we need to override equals() and hashCode() for SimpleHashMap itself? 56. * I don't know either:) 57. */ 58.}
发表评论
-
mysql中varchar类型转换Integer
2011-11-24 15:22 1243CAST(varchar字段 AS SIGNED) -
java 添加和清除cookie
2011-10-24 09:38 2066//添加cookie Cookie cookie = new ... -
java cookie操作
2011-10-24 09:34 1474Cookie概念: Cookie的格式实际上是一段纯文 ... -
java保留两位小数点(转)
2011-10-19 15:48 5719java保留两位小数问题: 方式一: 四舍五入 dou ... -
ibatis中批量删除
2011-09-15 10:27 1692Ibatis中批量删除方法: 方法一: 在映射文件中,按如 ... -
Java反射getFields()和getDeclaredFields()的区别
2011-09-05 13:23 1643Java反射 getFields()和getDeclaredF ... -
AES加密算法原理
2011-09-01 15:18 1740AES加密算法原理 随 ... -
Java AES加密实例
2011-09-01 14:30 3451package com.encrypt.hello; i ... -
Quartz任务中调用Spring容器中bean及动态调度任务
2011-08-31 15:09 19815Quartz 是开源任务调度框 ... -
Observer模式
2011-08-23 09:46 1033Java深入到一定程度,就不可避免的碰到设计模式(design ... -
Java环境下Memcached应用详解(转)
2011-08-22 10:05 0本文将对在Java环境下Memcached应用进行详细介绍。M ... -
Spring容器详解(转)
2011-08-22 09:53 1281我们在使用ssh整合项目的时候,Spring在其中是一个非常重 ... -
Spring DI(依赖注入) IOC(控制反转) AOP(面向切面编程)
2011-08-22 09:43 2124spring 的优点? 1.降低了 ... -
11款用于优化、分析源代码的Java工具
2011-08-08 15:13 891本文将提供一些工具, ... -
Java编程中影响性能的一些特点
2011-08-08 15:04 773文中将提供一些在Java编程中影响性能的一些特点,为了能够提高 ... -
Velocity基础
2011-08-08 11:01 1801Velocity 基础 Velocity是一个基于java的 ... -
java io经典例子
2011-08-03 14:45 1157IO是JAVASE中非常重要的一块,是面向对象的完美体现,深入 ... -
JUnit4详细教程
2011-08-02 15:36 1228因jdk5中的新特性,JUn ... -
JUnit4注解
2011-08-02 15:31 1018JUnit4注解 JUnit4的测试类不用再继承TestCa ... -
JUnit简明手册
2011-08-02 15:29 890用XP进行开发的过程,unit test是必不可少的环节。作为 ...
相关推荐
"Java重写equals及hashcode方法流程解析" Java中的equals和hashCode方法是两个非常重要的方法,它们都是Object类中的方法。在实际开发中,正确地重写这两个方法对于确保程序的正确性和性能至关重要。下面,我们将...
* 覆写 hashcode 方法,需要把某个非零常数值,例如 17,保存在 int 变量 result 中。 * 对于对象中每一个关键域 f(指 equals 方法中考虑的每一个域): + 对于 boolean 型,计算(f? 0 : 1)。 + 对于 byte,char,...
当覆写对象的equals()方法时必须同时覆写hashCode()方法。equals和hashCode方法是对象在hash容器内高效工作的基础,正确的覆写这两个方法才能保证在hash容器内查找对象的正确性。 遵循这些军规可以确保Java开发的...
- **解释**:当一个对象的equals()方法被覆写后,如果没有同时覆写hashCode()方法,可能会导致该对象在哈希表中的行为不符合预期。 - **实践建议**:确保equals()和hashCode()方法的一致性,以避免潜在的问题。 ###...
为了优化Map的性能,对象在作为键使用时,通常需要覆写hashCode()和equals()方法,确保当两个键被视为相等时,它们的哈希码也相同。 总结,Java集合框架为开发者提供了灵活的数据组织方式,无论是在简单的数据管理...
为了在HashMap中高效地定位键值对,键对象需要覆写hashCode()方法,确保不同的键返回不同的哈希值,减少冲突。 1.5 SET Set接口继承自Collection,不允许重复元素,如HashSet和TreeSet是其典型实现。Set接口的实现...
- 覆写equals方法时要处理null值,同时覆写hashcode以保持一致性。 - 推荐覆写toString方法,提供更友好的输出。 - 使用package-info.java为包提供元数据。 4. **字符串操作**: - 使用字符串直接量赋值,提高...
2. **覆写 hashCode 方法**:为了确保相等的对象有相同的哈希码,你需要在重写 `equals` 方法的同时,也重写 `hashCode` 方法。可以参考包装类(Wrapper Classes)中的实现。 **对象的复制** 1. **Object 类的 ...
2. **覆写hashCode**:确保相等的对象有相同的哈希码,不相等的对象有不同哈希码,以保证集合类的行为正确。 3. **始终覆写toString**:提供对象状态的简洁表示,有助于调试和日志记录。 4. **小心覆写clone**:`...
军规八:覆写对象的 equals() 方法时必须同时覆写 hashCode() 方法。这是因为当对象被添加到集合中时,需要使用 hashCode() 方法来判断对象的唯一性。 军规九:禁止循环中创建新线程,尽量使用线程池。这是因为循环...
- **覆写hashCode()**:为了确保键的唯一性,当使用自定义对象作为键时,需要重写equals()和hashCode()方法。 5. **Set** - Set接口不包含重复元素,且不保证元素顺序。 - **实现原理**:HashSet是最常见的Set...
1.4.4 覆写hashCode() 为了保证Map的正确工作,键对象必须实现equals()和hashCode()方法,使得相等的键返回相同的哈希码,这样在Map中查找时能正确找到对应的键值对。 总结来说,Java集合框架提供了丰富的数据结构...
为了保证元素的唯一性,存储在HashSet中的对象必须正确地覆写hashCode和equals方法。TreeSet利用二叉树的原理对元素进行排序,它可以将元素按照指定的顺序进行排序。如果需要对自定义对象进行排序,则要求该对象必须...
##### 4.4 覆写hashCode() 为了确保Map能够正确工作,如果作为键的类没有重写`hashCode()`方法,则可能会导致Map行为异常。因此,通常需要覆写`hashCode()`和`equals()`方法以确保正确的键值匹配。 #### 五、Set ...
#### 1.4.5 覆写hashCode() 为了确保`HashMap`的正确性,键对象需要正确覆写`hashCode()`和`equals()`方法。 ### 1.5 Set `Set`是不允许重复元素的`Collection`,通常用于需要唯一性保证的场景。 #### 1.5.1 ...
避免使用Java内置关键字或具有特殊含义的方法名,例如`equals`、`hashCode`、`clone`、`finalize`等,除非你确实需要覆写这些方法。 **2.1.3 Java Bean的boolean属性** 对于Java Bean中的boolean属性,访问器方法应...
此外,使用HashMap进行数据存储时,自定义键对象需要正确覆写hashCode()和equals()方法,以保证集合操作的正确性和效率。 单元测试优化主要关注测试的有效性和执行效率。一个良好的测试策略可以快速定位问题,保障...