关于hash(java)

  1. hashmap中key的类型,实现hashmap的put和get方法
    key只能为引用数据类型,不能为基本类型
    原理【基于hashing的原理的散列桶(数组和链表),通过put()和get()方法储存和获取对象,将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,让后找到bucket位置来储存值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。】
    特性:存储键值对,非synchronized(速度快),可以接受null键和值,采用链表解决冲突。
    HashMap存储(put)原理:(put的三种情况)
  1. 如果key为null,则将key-value对放在数组第一个位置
  2. 根据key的hashCode重新计算hash值,根据hash值得到元素在数组中的位置(下标index)。
  3. (1)遍历该位置上的链表,如果找到Key相等的元素,那么修改该元素的Value值;(2)否则将新元素添加链表的链尾(JDK1.8之前插入在链头,JDK1.8及以后插入在链尾)。
  4. 根据key计算出来的hash值,将key-value对添加到i索引处。
    HashMap读取(get)原理:
  5. 由Key的hashCode计算hash值,根据hash值得到在数组中的位置。
  6. 遍历数组中对应位置的链表,寻找相同Key值元素,并返回器其Value值。
  1. Concurrenthashmap和hashmap的区别,如何扩容
    Concurrenthashmap和hashmap的区别:
    1) 线程安全。ConcurrentHashMap是线程安全的,它将map分为若干个Segment(分段),在每个Segment使用ReentrantLock保护,相对于HashTable的synchronized锁粒度更加精细、并发性能更好。
    2) null值。HashMap允许Key和Value为null,而ConcurrentHashMap的Key和Value均不允许为null。
    扩容
    扩容时机:阈值threshold=容量*负载因子。当HashMap中元素数目达到阈值时,就会进行扩容。
    扩容幅度:每次扩容时size乘以2。
    性能消耗:扩容会带来性能消耗,每次扩容时原数组中的数据均要重新计算其在数组中的位置,并放进去。
    扩容上限:扩容有上限,数组最大长度为2的30次幂。
    HashMap有两个参数影响其性能:初始容量和负载因子,都可以通过构造器来设定其大小,默认构造器初始容量为16,负载因子为0.75。
    负载因子=散列表中实际元素数目/散列表容量。负载因子衡量散列表的空间使用程度,负载因子越大,对空间利用越充分,然而后果是查找效率降低(个人理解是因为,负载因子较高,说明冲突情况也比较多)。
  2. 与hashtable的区别:
    1)HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行。2) Hashtable是线程安全的,多个线程可以共享一个Hashtable;如果没有正确的同步的话,多个线程是不能共享HashMap的。3)HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。4)Hashtable在单线程环境下它比HashMap要慢。4)HashMap不能保证随着时间的推移Map中的元素次序是不变的
  3. 与hashSet的区别
  4. Hashmap的put为什么在高并发场景下会产生死循环
    多线程下HashMap resize()会出现死循环:HashMap的resize()对数组中每个链表采用的是遍历方式进行重新确定下标的,遍历时会使用“e = next;”
    fail-fast策略:由于HashMap线程是不安全的,那么如果在使用迭代器遍历map的过程中,如果有其它线程修改了map那么会抛出ConcurrentModificationException异常,这就是所谓的fail-fast策略。(在源码中会比较modCount与expectedModCount域来判断有没有其它线程修改map)
  5. 解决hash冲突的方法,各有什么优缺点
    解决hash冲突的方法:开放定址法(线性探测再散列, 随机探测再散列);拉链法;在哈希法(当发生冲突时,使用第二个、第三个、哈希函数计算地址,直到无冲突时。缺点:计算时间增加。);
    拉链法的优点:
    (1)处理冲突简单,没有堆积现象,平均查找长度较短
    (2)拉链法中的链表上的节点空间是动态申请的,适合于创造表之前无法确定表长的情况
    (3)开放定址法为了减少冲突,要求装填因子较小,节点规模大时会浪费空间,结点较大时,拉链法中增加的指针域可以忽略不计,节省空间
    (4)用拉链法构造的散列表中,删除节点的操作易于实现,只要删掉相应节点就可以,而开放地址构造的散列表,不能直接将对应位置质控,否则将截断在它之后填入的冲突的节点的查找。
    拉链法的缺点:指针需要额外的空间,节点规模较小,开放定址法较为节省空间。
  6. 数据结构hashmap不用map如何实现
  7. 哈希算法:除法hash(hash(key) = key mod M),乘法hash(hash(key) = floor( M/W * ( a * key mod W) )),斐波那契hash(当 “乘法哈希法” 的 a ≈ W/φ,1/φ ≈ (√5-1)/2 = 0.618 033 988 时情况)
  8. 为什么hashmap的长度要保持2的n方
    1) hashmap传入key值,计算位置的时候是 key.hash&length-1,我们的数组长度为16,那么16-1的二进制就是111的形式,key&111… 操作很快
    2) 它也保证了数组所有位置都可以被存放数据,节省了空间

你可能感兴趣的:(java)