java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java HashSet和HashMap

Java HashSet(散列集),HashMap(散列映射)的简单介绍

作者:dylan''''s blog

这篇文章主要介绍了Java HashSet(散列集),HashMap(散列映射)的简单介绍,帮助大家更好的理解和学习Java集合框架的相关知识,感兴趣的朋友可以了解下

简介

本篇将简单讲解Java集合框架中的HashSet与HashMap。

散列集(HashSet)

快速入门

private transient HashMap<E,Object> map;

public HashSet() {
 map = new HashMap<>();
}

public boolean add(E e) {
 return map.put(e, PRESENT)==null;
}

public Iterator<E> iterator() {
  return map.keySet().iterator();
}

散列表

字符串 散列码
"Lee" 76268
"lee" 107020
"eel" 100300

散列映射(HashMap)

快速入门

// HashMap.java源码
// 基于单向链表的用于存储数据的对象
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;
 }
 ...
}

// 基于红黑树的用于存储数据的对象
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
 TreeNode<K,V> parent; // red-black tree links
 TreeNode<K,V> left;
 TreeNode<K,V> right;
 TreeNode<K,V> prev; // needed to unlink next upon deletion
 boolean red;
 TreeNode(int hash, K key, V val, Node<K,V> next) {
  super(hash, key, val, next);
 }
 ...
}

二次散列

散列映射HashMap只对键进行散列,与键关联的值不进行散列。以下为HashMap中的部分源码:

public V put(K key, V value) {
 return putVal(hash(key), key, value, false, true);
}

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

扩容机制

final Node<K,V>[] resize() {
 Node<K,V>[] oldTab = table;
 int oldCap = (oldTab == null) ? 0 : oldTab.length;
 int oldThr = threshold;
 int newCap, newThr = 0;
 if (oldCap > 0) {
  if (oldCap >= MAXIMUM_CAPACITY) {
   threshold = Integer.MAX_VALUE;
   return oldTab;
  }
  else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
     oldCap >= DEFAULT_INITIAL_CAPACITY)
   newThr = oldThr << 1; // double threshold
 }
 else if (oldThr > 0) // initial capacity was placed in threshold
  newCap = oldThr;
 else {    // zero initial threshold signifies using defaults
  newCap = DEFAULT_INITIAL_CAPACITY;
  newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
 }
 if (newThr == 0) {
  float ft = (float)newCap * loadFactor;
  newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
     (int)ft : Integer.MAX_VALUE);
 }
 threshold = newThr;
 @SuppressWarnings({"rawtypes","unchecked"})
 Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
 table = newTab;
 if (oldTab != null) {
  for (int j = 0; j < oldCap; ++j) {
   Node<K,V> e;
   if ((e = oldTab[j]) != null) {
    oldTab[j] = null;
    if (e.next == null)
     newTab[e.hash & (newCap - 1)] = e;
    else if (e instanceof TreeNode)
     ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
    else { // preserve order
     Node<K,V> loHead = null, loTail = null;
     Node<K,V> hiHead = null, hiTail = null;
     Node<K,V> next;
     do {
      next = e.next;
      if ((e.hash & oldCap) == 0) {
       if (loTail == null)
        loHead = e;
       else
        loTail.next = e;
       loTail = e;
      }
      else {
       if (hiTail == null)
        hiHead = e;
       else
        hiTail.next = e;
       hiTail = e;
      }
     } while ((e = next) != null);
     if (loTail != null) {
      loTail.next = null;
      newTab[j] = loHead;
     }
     if (hiTail != null) {
      hiTail.next = null;
      newTab[j + oldCap] = hiHead;
     }
    }
   }
  }
 }
 return newTab;
}

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
    boolean evict) {
 Node<K,V>[] tab; Node<K,V> p; int n, i;
 if ((tab = table) == null || (n = tab.length) == 0)
  n = (tab = resize()).length; // 第一个resize()是进行动态数组Node<K, V>[]初始化的操作,不会进行扩容
 if ((p = tab[i = (n - 1) & hash]) == null)
  tab[i] = newNode(hash, key, value, null);
 else {
  Node<K,V> e; K k;
  if (p.hash == hash &&
   ((k = p.key) == key || (key != null && key.equals(k))))
   e = p;
  else if (p instanceof TreeNode)
   e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
  else {
   for (int binCount = 0; ; ++binCount) {
    if ((e = p.next) == null) {
     p.next = newNode(hash, key, value, null);
     if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
      treeifyBin(tab, hash);
     break;
    }
    if (e.hash == hash &&
     ((k = e.key) == key || (key != null && key.equals(k))))
     break;
    p = e;
   }
  }
  if (e != null) { // existing mapping for key
   V oldValue = e.value;
   if (!onlyIfAbsent || oldValue == null)
    e.value = value;
   afterNodeAccess(e);
   return oldValue;
  }
 }
 ++modCount;
 // 当HashMap中元素数量大于阈值threshold,则会进行扩容resize()操作
 if (++size > threshold)
  resize();
 afterNodeInsertion(evict);
 return null;
}
newCap = DEFAULT_INITIAL_CAPACITY; // DEFAULT_INITIAL_CAPACITY = 1 << 4,即默认大小为16。
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); // threshold = newCap * 0.75,即默认为12。
if (oldCap > 0) { // 当动态数组拥有默认容量时,如果再次调用resize(),则一定会进行扩容操作
 if (oldCap >= MAXIMUM_CAPACITY) {
  threshold = Integer.MAX_VALUE;
  return oldTab;
 } else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) { // 容量为原来的2倍
  newThr = oldThr << 1; // 阈值为原来的2倍
 }
}

总结

以上为所有关于HashSet、HashMap的粗略介绍。
如果希望了解更多的内容,可以前往JDK阅读源码。

以上就是Java HashSet(散列集),HashMap(散列映射)的简单介绍的详细内容,更多关于Java HashSet和HashMap的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文