HashMap总结(不包括红黑树)

总结:

  1. HashMap是用来存放key-value的容器,底层是使用数组+(链表/红黑树)实现的(节点少时(默认是UNTREEIFY_THRESHOLD = 6值)用链表,多时(默认是>TREEIFY_THRESHOLD = 8)用红黑树,),树化容量为MIN_TREEIFY_CAPACITY,默认是64。
  2. 成员变量:
    • table[]:存放Node的数组,一般称其为”桶”,table容量的大小也成为”桶”的大小,其容量必须为2的次幂默认值是DEFAULT_INITIAL_CAPACITY = 16
    • entrySet: HashMap有三种方式来遍历其存储的节点,一种是只遍历节点的key,一种是只遍历节点的value,还有一种是以“key=value”的形式遍历的,而entrySet就负责最后一种的显示方式,但是不管是哪种遍历方式,都是直接对原HashMap容器进行访问。
    • threshold:resize的阀值,其值为table容量*loadFactor
    • loadFactor:装载因子,默认是0.75f
  3. 构造器:
    • 前三个构造器只是用来指定threshold和loadFactor的值,并不会用来初始化table。并且必须满足threshold为2的次幂(通过tableSizeFor(int cap)方法)。
    • 第四个构造器用一个已经存在的Map来初始化当前HashMap
  4. 内部类:HashMap内部类主要是用来定义链表节点和树节点,key的集合与value的集合,以及三种方式迭代器的定义。

    • Node和TreeNode:分别用来定义链表节点和树节点;Node中的存放该节点的hash值,该节点的key,value值以及该节点的下一跳。需要说明的是Node节点的hash值与key的hash值一样,而且不是Node节点中hashCode()方法的值(hashCode()的值为key与value的哈希值取异或)
    • keySet,Values,EntrySet:分别是该HashMap的key集合,value集合以及形式为“key=value”的集合。他们三个虽然都称作集合,但就像上文所说:不管是哪种遍历方式,都是直接对原HashMap容器进行访问,其内部并没有成员变量。三者的小区别如下:
      • keySet类是AbstractSet的子类,利用Set的特点(无序不可重复,但是可以为null)可以保证key值都是不重复的。其对应的成员变量是HashMap的父类AbstractMap中声明的keySet变量;对应的方法是keySet()方法;对应的迭代器是KeyIterator迭代器。
      • Values类是AbstractCollection的子类,所以value值是可以重复的,也可以为null。其对应的变量是HashMap的父类AbstractMap声明的values变量;对应的方法是values()方法;对应的迭代器是ValueIterator迭代器。
      • EntrySet类是AbstractSet<Map.Entry<K,V>>的子类,Map.Entry类将Map的key,value转成一个个体(具体是什么类型由实现Map.Entry这个接口的类来说说明)。其对应的成员变量是HashMap(注意不是其父类的了)中的entrySet;对应的方法是entrySet()方法;对应的迭代器是EntryIterator迭代器。
    • HashIterator,KeyIterator,ValueIterator,EntryIterator:普通迭代器的四个内部类,HashIterator为一个抽象类,是另外三个类的父类。
      • HashIterator:需要注意这个类虽然叫iterator,但是并没有实现iterator接口,也就是说这是个‘伪迭代器’。其中的next成员变量为要访问的下一个节点,一开始指向table数组中第一个不为null的槽位的第一个节点;current为刚访问过的节点,一开始指向null并且每次调用remove()方法都会将current置为null。而在方法中有一个核心的方法叫nextNode(),作用是返回下一个节点并且将next后移,current指向刚刚访问的这个节点。
      • KeyIterator,ValueIterator,EntryIterator三个类继承了HashIterator并且实现了iterator接口(也就是说这三个才是真正的迭代器),他们的next()方法分别借助父类的nextNode()返回的节点来获取下一个节点key/value/entrySet。
    • HashMapSpliterator,KeySpliterator,ValueSpliterator,EntrySpliterator:并行遍历迭代器(水平不够分析不了)
  5. 方法:前文分析源码时所有重要的方法都已标出来了

    • hash(Object key):设置key值的hash值,如果key值为null,那么hash值为0;反之hash为调用Object.hashCode()方法得到的hash值的高16位与低16位进行异或(至于为什么要让他俩异或,其实没有太多原因,只是为了能让hashCode()的每一位都尽量能参与到后续hash函数的运算)
    • tableSizeFor(int cap):前文已经详细说明了,这里就不再重复了;复习的时候好好体会一下
    • crud操作:
      • 查:get(Object key) / containsKey(Object key) / containsValue(Object value) / getOrDefault(Object key, V defaultValue):得到key值对应的value / 判断是否有这个key值 / 判断是否有这个value值 / 得到key值的value值,如果不存在此key值返回defaultValue。
      • 增:put(K key,V value) / putAll(Map<? extends K, ? extends V> m) / putIfAbsent(K key, V value):往HashMap中放入一个节点,如果已存在该节点(key值已存在),那么将其value修改为value / 往HashMap中添加另一个容器m的所有节点,并且如果key值冲突,那么将value值设置为m中的value / 如果key值不存在,那么放入一个节点,如果存在返回原来的节点。
      • 删:remove(Object key) / clear() / remove(Object key, Object value):删除键为key的节点 / 清空HashMap / 只有容器中的key,value与参数的key,value同时相等时才移除。
      • 改(一般用增操作就替代了改操作):replace(K key, V oldValue, V newValue) / replace(K key, V value):只有容器中的key,value与参数的key,oldValue同时相等时才替换成newValue / 将key的value替换成参数的value
    • resize()/putVal():非常重要,虽然不能调用,但是和tableSizeFor一样;复习的时候好好体会,这是table扩容和放入节点的底层实现。
    • treeifyBin(Node<K, V>[], int):将链表转为红黑树(暂时跳过)。
    • clone()方法会浅表赋值一份,并且返回的是Object,还需要强转。
  6. 总结插入操作(不考虑红黑树)/删改查同理:

    • 当调用put(K key,V value)时,首先通过key,value创建一个Node,Node的hash值为hash(key),并且根据此hash值的二进制的低n位(n为log2(table.length)),并以此低n位转换成的table下标。将Node放入这个”槽”中(每个槽都是一个链表)。
    • 挨个与该”槽”中的每个节点进行判断操作,如果有key值相等的,那么直接修改其value值;如果没有key值相等的,往链表最后加入该节点,同时size++;
  7. 总结resize():

    • 每次扩容时,其扩容的table.length为原来的两倍。
      + 并且对原table的每个槽位的链表进行遍历,每个链表都会拆成两个链表(如果可以的话),其一还是存放在下标为原来的,其二是存放到下标为原来的+扩容的。
  8. 总结迭代器的实现:

    • 当new出一个迭代器时,迭代器的next指向第一个不为空的table槽的第一个节点的起点,然后依次遍历。
    • next()方法会让返回next值并且next后移一位,current指向刚访问过的节点(底层调用nextNode()实现的),而当后移过后的next为null时,说明该槽位的所有节点已经都访问过,那么next会指向下一个不为空的table槽的第一个节点的起点。
    • remove()操作会移除刚刚访问的这个节点,并且将current置为null
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值