Featured image of post Java集合(2)

Java集合(2)

1885 words

HashMap和Hashtable的区别

HashMap和HashSet的区别

HashMap和TreeMap的区别

HashSet如何检查重复

HashMap的底层实现

HashMap的长度为啥是2的幂次方

HashMap多线程操作导致死循环问题

HashMap为啥线程不安全

HashMap的遍历方式有哪些?

HashMap和Hashtable的区别

  • 线程是否安全,HashMap的线程是不安全的,Hashtable的线程是安全的。
  • 效率:因为线程安全的问题,HashMap要比Hashtable的效率高一点。另外,Hashtable被淘汰了。
  • HashMap可以有一个null键和多个null值,但HashTable不允许有null键和null值。
  • 哈希函数的实现: HashMap对哈希值进行了高位和低位的混合扰动处理以减少冲突,而Hashtable直接使用键的hashCode()值。

HashMap和HashSet的区别

  • HashMap存储键值对,HashSet仅仅存储对象。
  • HashMap实现Map接口,HashSet实现了Set接口。
  • HashMap调用put()向map添加元素,HashSet调用add()方法向Set中添加元素。

HashMap和TreeMap的区别

  • 相对于HashMap实现了AbstractMap,TreeMap还实现了NaivgableMap接口和SortedMap接口。
  • 实现的Naivgable让TreeMap有了对集合内元素的搜索的能力。
  • 实现SortedMap接口让TreeMap有了对集合中的元素根据键排序的能力。

HashSet如何检查重复

当你把对象加入HashSet时,HashSet 会先计算对象的hashcode值来判断对象加入的位置,同时也会与其他加入的对象的 hashcode 值作比较,如果没有相符的 hashcode,HashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让加入操作成功。

HashMap的底层实现

HashMap的底层代码分析与实现

HashMap的长度为啥是2的幂次方

  • 位运算效率更高: 位运算(&)比取余运算(%)更高效。当长度为2的幂次方相较于%length,&(length - 1)等价。
  • 可以更好地保证哈希值的均匀分布:扩容之后,在旧数组元素hash值比较均匀的情况下,新数组元素也会被分配的比较均匀。
  • 对于每次的扩容,不需要其他的操作,仅仅需要根据高危的变化进行重新分配(如果高位是1,则原位置 + 扩容的容量,高位是0,则位置不变)。

HashMap多线程操作导致死循环问题

  • JDK1.7及之前的版本导致的死循环问题的原因是当一个桶位中有多个元素需要进行扩容时,多个线程同时对链表进行操作,头插法可能会导致链表中的节点指向错误的位置,从而形成一个环形链表,进而使得查询元素的操作陷入死循环无法结束。
  • 而对于HashMap会出现数据覆盖的结果,所以在多线程也不推荐HashMap。

HashMap为啥线程不安全

  • 两个线程同时put操作导致size的值不正确,进而导致数据覆盖的问题。
  • 在 HashMap 中,多个键值对可能会被分配到同一个桶(bucket),并以链表或红黑树的形式存储。多个线程对 HashMap 的 put 操作会导致线程不安全,具体来说会有数据覆盖的风险。

HashMap的遍历方式有哪些?

  • 迭代器EntrySet方式:通过获取HashMap的entrySet集合,然后使用迭代器进行遍历。这种方式可以同时访问键和值。

  • 迭代器KeySet方式:通过获取HashMap的keySet集合,然后使用迭代器进行遍历。这种方式只能访问键,需要通过键来获取对应的值。

  • ForEach EntrySet方式:使用增强型for循环直接遍历HashMap的entrySet集合。这种方式同样可以同时访问键和值。

  • ForEach KeySet方式:使用增强型for循环直接遍历HashMap的keySet集合。这种方式只能访问键,需要通过键来获取对应的值。

  • Lambda表达式方式:通过使用Lambda表达式对HashMap中的每个元素进行处理。这种方式代码简洁,易于理解。

  • Streams API单线程方式:使用Streams API的stream()方法将HashMap转换为流,然后使用forEach方法进行遍历。这种方式适用于单线程环境。

  • Streams API多线程方式:使用Streams API的parallelStream()方法将HashMap转换为并行流,然后使用forEach方法进行遍历。这种方式适用于多线程环境,可以提高遍历效率。

使用 Hugo 构建
主题 StackJimmy 设计