Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

happyflyer/Java-HashMap

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

1 Commit

Repository files navigation

1. 目标

  • 学习 HashMap 的构造方法、合适的遍历、复制转換等
  • 学习 HashMap 必须要知道的底层原理
  • TreeMap、LinkedHashMap 比 HashMap 更好吗?
  • 看图说话,对比各 Map 实现类的速度

2. 内容

  • HashMap
    • HashMap 有几种构造方法?怎么用?
  • HashMap 底层原理
    • 存取的过程
    • 怎样进行初始化
    • 扩容
  • LinkedHashMap、TreeMap 的用法
  • 性能分析

3. Map 接口

Map接口

  • V put(K key, V value);
  • V get(Object key);
  • int size();
  • V remove(Object key);
  • boolean containsKey(Object key);
static class Entry<K, V> implements Map.Entry<K, V> {
 final K key;
 V value;
 Entry<K, V> next;
 final int hash;
}

4. get 操作性能对比

实验结果:entrySet() 优于 Iterator 优于 values() 优于 keySet()

4.1. keySet()

for (String key : userMap.keySet()) {
 value = userMap.get(key);
}

4.2. values()

for (Integer v : userMap.values()) {
 value = v;
}

4.3. entrySet()

for (Map.Entry<String, Integer> entry : userMap.entrySet()) {
 value = entry.getValue();
}

4.4. Iterator

Iterator<Map.Entry<String, Integer>> it = userMap.entrySet().iterator();
while (it.hasNext()) {
 Entry<String, Integer> entry = it.next();
 value = entry.getValue();
}

5. HashMap 底层原理

  • 了解 HashMap 底层原理是每个 Java 工程师的必修课
  • 可以更好的进行 HashMap 的优化设计
  • 与行业内同事沟通交流的话题

5.1. 一个例子

Map<Integer, String> intMap = new HashMap<>();
intMap.put(120, "a");
intMap.put(37, "b");
intMap.put(61, "c");
intMap.put(40, "d");
intMap.put(92, "e");
intMap.put(78, "f");
{37=b, 120=a, 40=d, 92=e, 61=c, 78=f}

HashMap底层原理

5.2. 两个关键方法

Map<String, Integer> strMap = new HashMap<>();
strMap.put("yuwen", 90);
strMap.put("yinyue", 78);
strMap.put("tiyu", 88);
strMap.put("shuxue", 60);
strMap.put("meishu", 98);
{yuwen=90, shuxue=60, tiyu=88, yinyue=78, meishu=98}

5.2.1. hash

static final int hash(Object key);

hashCode() 方法将 key 转换成 hash 码后并进行优化得到优化后的 hash 码

例如:将 yuwen 这个字符串优化后的 hash 码是 115347492

5.2.2. indexFor

static final int indexFor(int h, int length);

对优化后的 hash 码,进行取址,确定在 HashMap 的位置。

例如:115347492 在长度是 16 的 HashMap 中,取址的坐标是 4

5.3. 三个构造方法

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
static final float DEFAULT_LOAD_FACTOR = 0.75f;
  • public HashMap()
  • public HashMap(int initialCapacity)
  • public HashMap(int initialCapacity, float loadFactor)

HashMap扩容

  • new HashMap(5),初始化的长度就是 5ドル$ 吗?

初始化长度为传入长度的最小的 2ドル$$n$ 次方,初始化长度为 8ドル$

  • new HashMap(10000, 0.75),要录入的数据有 10000ドル$ 条,会产生扩容吗?

初始化长度为 2ドル^{14} = 16384$,扩容长度为 16384ドル \times 0.75 = 12288$,不会扩容。

/**
 * 1、创建 10 个 HashMap,每个 HashMap 含有 10w 条记录
 * 2、传递不通的构造方法的参数,比较速度
 * 3、实验参数:构造方法传参 (16, 0.75f) 和 (16384, 0.75f)
 */

initialCapacity 的设置要合适,适应业务需求,尽量避免扩容。

5.4. 常用方法

  • 判断是否为空、删除结点、清空 HashMap 对象
  • 判断是否有某个 key、判断是否有某个 value
  • HashMap 替换某个 key 的 value
/**
 * 用到的技术点:
 * 1、isEmpty
 * 2、remove, clear
 * 3、containsKey, containValue
 * 4、replace
 * 5、put, putIfAbsent
 * 6、forEach((key, value) -> System.out.println(key + ": " + value))
 * 7、getOrDefault(Object key, V defaultValue)
 */
  • boolean isEmpty();
  • V remove(Object key);
  • void clear();
  • boolean containsKey(Object key);
  • boolean containsValue(Object value);
  • default V replace(K key, V value)
  • default boolean replace(K key, V oldValue, V newValue)
  • V put(K key, V value);
  • default V putIfAbsent(K key, V value)
  • default void forEach(BiConsumer<? super K, ? super V> action)
  • default V getOrDefault(Object key, V defaultValue)

6. LinkedHashMap

6.1. 对比实验

/**
 * 1、分别给 HashMap 和 LinkedHashMap 录入 100w 条记录,并循环遍历,观察耗时
 * 2、都采用不带参的空构造方法
 */
  • put 操作:HashMap 优于 LinkedHashMap
  • get 操作:LinkedHashMap 优于 HashMap

6.2. 两种输出顺序

  • 录入顺序
  • 使用顺序
public LinkedHashMap(int initialCapacity,
 float loadFactor,
 boolean accessOrder)
new LinkedHashMap<>(16, 0.75f, true)

6.3. 利用 LinkedHashMap 实现 LRU

public class LruMap<K, V> extends LinkedHashMap<K, V> {
 private int maxSize;
 public LruMap(int maxSize) {
 super(16, 0.75f, true);
 this.maxSize = maxSize;
 }
 @Override
 protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
 return size() > this.maxSize;
 }
}

7. TreeMap

  • 对 TreeMap 实现增、删、遍历、排序等操作
  • 存取耗时对比
    • put 操作:HashMap 优于 LinkedHashMap 优于 TreeMap
    • get 操作:LinkedHashMap 优于 TreeMap 优于 HashMap

Releases

No releases published

Packages

No packages published

Languages

AltStyle によって変換されたページ (->オリジナル) /