java之HashMap

117 阅读3分钟

hashmap是java中一个很重要的知识点,今天来简单讲解一下.

hashmap底层存储数据: 数组+链表+红黑树.

一个数据被存入到hashmap里面的时候首先要经过hashCode()的运算,然后经过一系列的算法,最终会得到一个值,这个值就代表该数据被存储的位置.

image.png 随着数据的增多,经过hashCode再经过一系列的算法,可能会得到相同的值,那么此时就需要用到链表了.

image.png 如果所示,假设位置2已经存储了数据,但是新增的数据经过hashCode和算法计算后得到的值仍然是2,那么就会在原来的基础上新增一个双向链表,这种方法叫做址链表法.如果后续还有相同,可以继续添加在后面.

如果通过址链表法添加的数据量达到一定程度,就会把链表变成红黑树,红黑树的目的是为了提高访问效率.

这里来说一下hashMap一些知识点.

hashMap数组长度必须是2的幂次方,如果初始化不是2的幂次方,编译器会自动帮你扩充到2的幂次方.

接下来说一下hashmap源码中的一些东西.

  1. DEFAULT_INITIAL_CAPACITY(default_initial_capacity) : hashmap数组长度, 默认值为16
  2. DEFAULT_LOAD_FACTOR = 0.75f(default_load_factor) : 默认加载因子,就是说一个数组中的数量达到这个数量后就会自动扩容.比如最开始的16,这里0.75,也就说如果数据有16*0.75=12个就会扩容.
  3. TREEIFY_THRESHOLD(treeify_threshold) : 链表转红黑树阈值,只有链表达到这个数才会转成红黑树. 默认值为8
  4. UNTREEIFY_THRESHOLD(untreeify_threshold): 红黑树转链表阈值 : 当红黑树中数据减少到该值的时候就会自动转成链表.
  5. MIN_TREEIFY_CAPACITY(min_treeify_capacity) : 链表转红黑树hash表最小容量阈值,达不到先扩容.意思就是如果hash数组中的容量没有达到该值,链表不会转成红黑树.

关于hashmap中重写euqals和hashCode方法.

使用hashmap存储数据就必须在对应的类里面重写equals和hashCode方法,为了确保hashmap中Key的唯一性.

关于重写equals方法,equals方法本身比较的是地址,如果重写了比较的就是对象内部的数据,而不是地址.

关于重写equals方法就必须重写hashCode方法.如果重写了equals方法,比较的就是两个对象内部数据是否相等,而不是内存地址了,那么没有被重写的hashCode方法会当做两个不同的对象进行计算,最后所得出来的就不是一个hash值,也就会直接存储在hashmap里面,但是由于两个对象里面的数据是一样的只是内存地址不一样而已,这样就会产生一个悖论,equals方法相同的对象有不同的hash值,而重写的hashCode方法就解决了这个问题,所以重写equals方法必须重写hashCode方法.

关于重写hashCode方法,JDK提供的hashCode方法计算的是对象地址,如果两个对象是同一个对象,就是说指针指向一样,那么hashCode值必定一样.重写后的hashCode计算的是对象内部数据,不管两个对象内存地址如何,只要内部数据相等,那么他们的hashCode值就必定一样.

image.png

image.png