九、散列与散列码

HashMap使用equals()判断当前的键是否与表中存在的键相同。

正确的equals()方法需满足一下条件:

1)自反性。x.equals(x) 是true;

2)对称性。x.equalse(y) 返回true y.equals(x)也得是true;

3)传递性。x.equals(y) 返回true ,y.equals(z) 返回true , x.equals(z)返回true;

4)一致性。如果对象中用于等价比较的信息没有变,那么无论多少次 x.equals(y)返回值不会变

5)x.equals(null) 返回 false ;注意:(null).equals(x)报空指针。

强调:默认的Object.equals()只比较对象的地址,因此如果使用自己的类作为HashMap的Key,必须同时重载hashCode()和equals()。

hashCode()并不需要总是能够返回唯一的标识码,但是equals()方法必须严格的判断两个对象是否相等,作为键必须唯一否则系统报错。

    @Override
    public boolean equals(Object o) {
        return o instanceof T && (i.equals(((T) o).i)));
    }

instanceof检查了此对象是否为null ,是null则返回false。

为速度而散列

以线性查询的是最慢的查询方式,存储一组元素最快的数据结构是数组,所以使用它来标识键的信息(注意,这里说的是键信息不是键本身)。

由于数组不能调整容量,所以数组不保存键本身,而是通过键对象生成一个散列码,将其作为数组的下标,这个散列码就是由Object中的、或自己的类覆盖的hashCode()生成的。

数组固定的问题解决了,但是键可以产生相同的下标,也就是说可能会有冲突。数组多大不重要,任何键总能在数组中找到它的位置。

于是,查询一个值的过程首先就是计算散列码,然后使用散列码查找数组。如果能够保证没有冲突(如果被查询的值的数量是固定的,就有可能)。

通常,冲突由外部链接处理;数组并不直接保存值,而是保存值的list。然后对list中的值使用equals()方法进行线性查询。

这部分查找会比较慢,但是如果散列函数好的话,数组每个位置就有较少的值。

因此,不是查询整个List而是快速的跳转到数组的某个位置,只对很少的元素进行比较。这就是HashMap会如此快的原因。 

我们把散列表的数组称为bucket(桶),为了散布均匀且速度快,桶的容积通常使用质数或者2的整数次方,用LinkedList填充桶。

put()操作,计算key的hashCode(),找到桶中的位置,看LinkedList内容,有值用equals()与值的key相比,相等就替换,不等或者没有值就在尾部加上新值。

覆盖hashCode()

桶下标值是无法控制的,这个值依赖于具体的HashMap对象的容量,而容量的改变与容器的充满程度和负载因子有关。hashCode()生成的结果,经过畜栏里后成为桶位的下标。

Joshua Blochw指出为写出一份像样的hashCode给出了知道:

1)给 int 变量 result 赋予某个非0常量,

2)为对象内每个有意义的域f(既每个可以做equals()操作的域)计算一个int 散列码 c:

域类型:                                                                 计算:

boolean                                                                   c=(f?0:1)

byte、char、short、int                                           c=(int)f

float                                                                         c=(int)(f^(f>>>32))

double                                                                     long I =Double.doubleToLongBits(f); c=(int)(I^(I>>>32))

Object,其equals()调用这个域的equals()       c=f.hashCode()

数组                     对每个元素应用上述规则   

3)合并计算得到散列码

result = 37*result+c                         

Java编程思想——第17章 容器深入研究 读书笔记(四)的更多相关文章

  1. Java编程思想——第17章 容器深入研究 读书笔记(三)

    七.队列 排队,先进先出. 除并发应用外Queue只有两个实现:LinkedList,PriorityQueue.他们的差异在于排序而非性能. 一些常用方法: 继承自Collection的方法: ad ...

  2. Java编程思想——第17章 容器深入研究 读书笔记(二)

    五.List的功能方法 排除Collection已包含的方法外还增加了 boolean addAll(int index, Collection<? extends E> c);从索引位置 ...

  3. Java编程思想——第17章 容器深入研究 读书笔记(一)

    这一章将学习散列机制是如何工作的,以及在使用散列容器时怎么样编写hashCode()和equals()方法. 一.容器分类 先上两张图 来概况完整的容器分类 再细说都为什么会有那些特性. 二.填充容器 ...

  4. Java编程思想——第17章 容器深入研究(two)

    六.队列 排队,先进先出.除并发应用外Queue只有两个实现:LinkedList,PriorityQueue.他们的差异在于排序而非性能. 一些常用方法: 继承自Collection的方法: add ...

  5. Java编程思想——第17章 容器深入研究(一)

    这一章将学习散列机制是如何工作的,以及在使用散列容器时怎么样编写hashCode()和equals()方法. 一.容器分类 先上两张图 来概况完整的容器分类 再细说都为什么会有那些特性. 二.Coll ...

  6. Java编程思想(11~17)

    [注:此博客旨在从<Java编程思想>这本书的目录结构上来检验自己的Java基础知识,只为笔记之用] 第十一章 持有对象 11.1 泛型和类型安全的容器>eg: List<St ...

  7. Java编程思想 第21章 并发

    这是在2013年的笔记整理.现在重新拿出来,放在网上,重新总结下. 两种基本的线程实现方式 以及中断 package thread; /** * * @author zjf * @create_tim ...

  8. Java编程思想——第14章 类型信息(一)

    运行时类型信息使得你可以在程序运行时发现和使用类型信息.Java是如何让我们在运行时识别对象和类的信息得呢? 主要有两种方式:1.传统RTTI,他假定我们在编译期间已经知道了所有类型:2.反射,它允许 ...

  9. Java编程思想(第一章 对象入门)总结

    面向对象编程(oop) 1.1抽象的进步 所有编程语言的最终目的都是提供一种“抽象”方法.   难点是 在机器模型(位于“方案空间”)和实际解决问题模型(位于“问题空间”)之间,程序员必须建立起一种联 ...

随机推荐

  1. Winform中使用FastReport实现自定义PDF打印预览

    场景 Winform中使用FastReport实现简单的自定义PDF导出: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1009 ...

  2. HDFS的快照原理和Hbase基于快照的表修复

    前一篇文章<HDFS和Hbase误删数据恢复>主要讲了hdfs的回收站机制和Hbase的删除策略.根据hbase的删除策略进行hbase的数据表恢复.本文主要介绍了hdfs的快照原理和根据 ...

  3. 【学习笔记】第六章 python核心技术与实践--深入浅出字符串

    [第五章]思考题答案,仅供参考: 思考题1:第一种方法更快,原因就是{}不需要去调用相关的函数: 思考题2:用列表作为key在这里是不被允许的,因为列表是一个动态变化的数据结构,字典当中的key要求是 ...

  4. 致初学者(四):HDU 2044~2050 递推专项习题解

    所谓递推,是指从已知的初始条件出发,依据某种递推关系,逐次推出所要求的各中间结果及最后结果.其中初始条件或是问题本身已经给定,或是通过对问题的分析与化简后确定.关于递推的知识可以参阅本博客中随笔“递推 ...

  5. 浅谈DanmakuView

      今天简单介绍一下开源的弹幕引擎---danmakuView   使用之前在build.gradle里面添加下面这一条(目前我使用的工具是AndroidStudio 3.1.2)   impleme ...

  6. 你好,C语言

    对于我来说,C语言就和陌生人一样,对他完全不了解,更不要提什么C++了,这就要我主动和他打招呼,深入认识了解它了哈.目前对于C语言的理解,只知道他的的功强大,能操作硬件,编写各类驱动,强悍的LINUX ...

  7. 认识HTML和CSS

    1.认识HTML标记 HTML的全称是Hyper text markup language,超文本标记语言,用于定义文档的内容结构.在HTML中,所有的标记都是成对出现的. <html>标 ...

  8. Asp.net Windows 身份验证-域验证

    一.在web.config中设置: <authentication mode="Windows" /> 二.获取计算机名\账户名 使用代码:HttpContext.Cu ...

  9. jenkins之插件下载方法

    jenkins插件下载方法有两种,在线下载和离线下载方式 在线下载 就是在安装好了jenkins之后,进入jenkins的插件管理页面,搜索想要的插件,点击安装即可 例如:安装git插件 问题:有时候 ...

  10. 配置eclipse编写html/js/css/jsp/java时自动提示

    配置eclipse编写html/js/css/jsp/java时自动提示步骤: 1.打开eclipse→Windows→Preferences→Java→Editor→Content Assist 修 ...