您的位置:

HashMap详解

一、HashMap原理

HashMap是基于哈希表的实现,它是一种将键映射到值的数据结构。

HashMap可以通过key来访问value,因此它提供了非常快速的(近似常数时间)查询操作。

HashMap采用数组、链表、红黑树结合的方式实现,数组被分为一个一个的桶,每个桶里面存放一条链表或者红黑树,当链表长度超过8,并且数组长度大于64时,链表就会转化为红黑树,这样可以提高查询效率。

二、HashMap和Map区别简答

Map是所有映射类型的基类,HashMap是Map接口的一种实现。

因此,HashMap继承了Map接口的所有属性和行为。在Java中,Map和HashMap都是非常常见的用于存储键值对的容器。

Map是一个映射接口,它提供了每个键都可以对应一个值的存储机制。HashMap是通过继承AbstractMap来实现的,而且它是一种基于哈希表的Map实现。

三、HashMap方法

HashMap提供了以下方法:

1. put(K key, V value):将指定的值与此映射中的指定键相关联。

2. get(Object key):返回此映射中指定键所映射的值。

3. remove(Object key):从此映射中移除指定键的映射。

4. containsKey(Object key):如果此映射包含指定键的映射,则返回true。

5. containsValue(Object value):如果此映射将一个或多个键映射到指定值,则返回true。

6. keySet():返回此映射中包含的键的Set视图。

7. values():返回此映射中包含的值的Collection视图。

8. entrySet():返回此映射中包含的映射的Set视图。

四、HashMap的理解

HashMap是一个用于存储键值对的数据结构,它提供了五种不同的存储方式:数组、链表、红黑树、字段元素、桶容量因子。其中,数组、链表和红黑树的实现来自于Java集合框架的LinkedList和TreeMap类,字段元素和桶容量因子则是HashMap独有的特性。

作为HashMap使用者,我们不需要了解HashMap内部的实现原理,只需要了解其提供的方法即可。但是如果想要深入了解Java集合框架,建议可以学习一下HashMap的源码实现。

五、HashMap的get方法

get方法是HashMap中最常用的方法之一,它用于返回与指定键相关联的值。在HashMap中,get方法可以通过以下步骤来完成:

1. 将key的hashCode作为参数入参传递给hash方法。

public V get(Object key) {
    Node e;
    return (e = getNode(hash(key), key)) == null ? null : e.value;
}

  

2. hash方法会将hashCode的高位异或低位,来保证一个更好的hash值分布,得到对应的桶的索引。

final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

3. 根据桶的索引定位到对应的桶,遍历桶中的链表,如果key相同,则返回对应的value。

final Node getNode(int hash, Object key) {
    Node
   [] tab;
    Node
     first, e;
    int n;
    K k;
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (first = tab[(n - 1) & hash]) != null) {
        if (first.hash == hash && // always check first node
            ((k = first.key) == key || (key != null && key.equals(k))))
            return first;
        if ((e = first.next) != null) {
            if (first instanceof TreeNode)
                return ((TreeNode
     )first).getTreeNode(hash, key);
            do {
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
            } while ((e = e.next) != null);
        }
    }
    return null;
}

     
    
   
  

六、HashMap用法

HashMap用法非常广泛,可以通过创建HashMap对象,调用其提供的put方法,向HashMap中添加键值对:

HashMap map = new HashMap<>();
map.put("apple", 1);
map.put("banana", 2);
map.put("orange", 3);

  

也可以通过get方法,从HashMap中获取指定键对应的值:

Integer value = map.get("apple");

七、HashMap集合说法正确的是

HashMap是一种无序的集合,它不保证集合中元素的顺序。

另外,HashMap中可以存储null值和null键。

八、HashMap集

HashMap是一种key-value的数据结构。

它的内部是通过哈希表的方式来存储数据的。

HashMap中的key和value都可以为null。

当HashMap中出现hash冲突的时候,会采用链表的方式来存储。

九、HashMap扩容

HashMap在存储元素的时候,存在一个负载因子(load factor)的概念。

当元素的数量达到负载因子与容量的乘积时,HashMap就会自动扩容。默认的负载因子是0.75,即当HashMap的元素数量达到容量的75%时,就会进行扩容。

在扩容的时候,HashMap会将元素重新分配到新的数组中。这个过程需要对每个元素重新计算hash值,因此效率较低。

十、HashMap源码选取

在HashMap中,我们可以看一下Node类的定义:

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;

    Node(int hash, K key, V value, Node<K,V> next) {
        this.hash = hash;
        this.key = key;
        this.value = value;
        this.next = next;
    }

    public final K getKey()        { return key; }
    public final V getValue()      { return value; }
    public final String toString() { return key + "=" + value; }

    public final int hashCode() {
        return Objects.hashCode(key) ^ Objects.hashCode(value);
    }

    public final V setValue(V newValue) {
        V oldValue = value;
        value = newValue;
        return oldValue;
    }

    public final boolean equals(Object o) {
        if (o == this)
            return true;
        if (o instanceof Map.Entry) {
            Map.Entry e = (Map.Entry)o;
            if (Objects.equals(key, e.getKey()) &&
                Objects.equals(value, e.getValue()))
                return true;
        }
        return false;
    }
}

Node类用于存储键值对,也就是哈希表中的元素。它包含了hashCode、key、value、next四个字段,其中hashCode是计算得到的键的哈希值,key和value分别对应键和值,next是指向下一个元素的指针。