《C#高效编程》读书笔记07-理解GetHashCode()的陷阱
GetHashCode()函数仅会在一个地方用到,即为基于散列(hash)
的集合定义的散列键时,此类集合包括HashSet和Dictionary<K,V>容器等。
但object基类提供的GetHashCode()实现有很多问题。
- 对于引用类型,虽然可以正常工作,但效率很低
- 对于值类型,基类中的实现有时甚至是不正确的
如果我们定义的类型不会在容器中作为键来使用,那就没有什么问题。但如果创建的类型将被当做散列表中的键使用,那么就需要自己实现GetHashCode()。
重载GetHashCode()必须遵循以下规则:
- 如果两个对象相对(由operator==定义),那么它们必须生成相同的散列码。否则,这样的散列码将无法用来查找容器中的对象。
- 对于任何一个对象A,A.GetHashCode()必须保持不变。不管在A上调用什么方法,A.GetHashCode()都必然总是返回同一个值。这可以确保放在“桶”中的对象总是位于正确的“桶”中。
- 对于所有的输入,散列函数应该在所有整数中按照随机分布生成散列码。这样散列容器才能得到足够的效率提升。
Object.GetHashCode()使用System.Object中的一个内部字段来产生序列值。系统创建的每一个对象在创建时都会被指派给一个唯一的对象键(一个整数值)。这些键从1开始,每创建一个任意类型的新对象,键值都会随之增长。对象标识字段会在System.Object构造函数中设置,并且之后不能更改。对于一个指定的对象,Object.GetHashCode()会返回该值作为散列码。
但其实Object.GetHashCode()并不满足第三条规则,一个递增序列在所有整数范围内显然不是一个随机分布。Object.GetHashCode()返回的散列码会集中在整数范围的低端。这就意味着Object.GetHashCode()的实现虽说是正确的,但效率不够好。
System.VauleType覆写GetHashCode()方法,为所有值类型提供了一个默认实现。默认的实现会返回类型中定义的第一个字段散列码。只有当值类型的第一个字段是只读的情况下,VauleType.GetHashCode()才能正常工作。只有当值类型第一个字段包含的值有着相对随机分布时,VauleType.GetHashCode()才会产生一个比较高效的散列码。
最新文章
- Memcached和Redis比较
- ExtJs动态生成treepanel的Json格式
- mamp pro
- linux shell ls -1 列显示文件
- 【WEB小工具】BaseServlet—一个Servlet处理多个请求
- MEF学习小结 z
- linux上安装memcached
- 插入ts以及判断列是否存在(支持多数据库)
- SGU 163.Wise King
- (转)android多国语言适配
- 当<;script>;中的type等于text/html的妙用
- C-Swipe Mobile 一个适用于Vue2.x的移动端轮播组件
- iOS网络编程笔记——GCDAsyncSocket使用
- iframe的缺点
- springBoot(7)---整合Mybaties增删改查
- windows Sever 2012下Oracle 12c安装配置方法图文教程
- socket 发送图片
- 总结:独立开发 jar 包组件——功能主要是支持查询数据库的所有表数据
- onsubmit return false仍提交表单
- 【数组】Jump Game
热门文章
- Qt webview调用JavaScript 带参函数
- Spring开发环境搭建
- spring 4.0 JUnit简单的Dao,Service测试
- Linux进程KILL不掉的原因
- 在虚拟机环境(CentOS7系统)下将kubernetes中部署服务成功,但在虚拟机外部无法访问到服务
- jquery抽奖插件+概率计算
- 使用 jquery.webcam 进行asp.net 拍照
- 序列化 (C#)
- centos运行netcore error:package: ‘Microsoft.AspNetCore.Antiforgery‘, version: ‘2.0.3‘
- jquery事件之事件委托和事件切换