建议多看源码,若是以为晦涩能够戳这里看源码解析。html
安利网址:http://www.admin10000.com/document/3322.html,我的以为分析的挺好java
JDK1.8之前,HashMap的put()方法、get()源码以下:node
put():mysql
public V put(K key, V value) { // HashMap容许存放null键和null值。 // 当key为null时,调用putForNullKey方法,将value放置在数组第一个位置。 if (key == null) return putForNullKey(value); // 根据key的hashCode从新计算hash值。 int hash = hash(key.hashCode()); // 搜索指定hash值所对应table中的索引。 int i = indexFor(hash, table.length); // 若是 i 索引处的 Entry 不为 null,经过循环不断遍历 e 元素的下一个元素。 for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } // 若是i索引处的Entry为null,代表此处尚未Entry。 // modCount记录HashMap中修改结构的次数 modCount++; // 将key、value添加到i索引处。 addEntry(hash, key, value, i); return null; }
get():算法
public V get(Object key) { // 若是 key 是 null,调用 getForNullKey 取出对应的 value if (key == null) return getForNullKey(); // 根据该 key 的 hashCode 值计算它的 hash 码 int hash = hash(key.hashCode()); // 直接取出 table 数组中指定索引处的值, for (Entry<K, V> e = table[indexFor(hash, table.length)]; e != null; // 搜索该 Entry 链的下一个 Entr e = e.next) // ① { Object k; // 若是该 Entry 的 key 与被搜索 key 相同 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null; }
JDK1.8+,HashMap的put()、get()方法源码以下:sql
put():数据库
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; // table未初始化或者长度为0,进行扩容 if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; // (n - 1) & hash 肯定元素存放在哪一个桶中,桶为空,新生成结点放入桶中(此时,这个结点是放在数组中) if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); // 桶中已经存在元素 else { Node<K,V> e; K k; // 比较桶中第一个元素(数组中的结点)的hash值相等,key相等 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) // 将第一个元素赋值给e,用e来记录 e = p; // hash值不相等,即key不相等;为红黑树结点 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; } // 判断链表中结点的key值与插入的元素的key值是否相等 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) // 相等,跳出循环 break; // 用于遍历桶中的链表,与前面的e = p.next组合,能够遍历链表 p = e; } } // 表示在桶中找到key值、hash值与插入元素相等的结点 if (e != null) { // 记录e的value V oldValue = e.value; // onlyIfAbsent为false或者旧值为null if (!onlyIfAbsent || oldValue == null) //用新值替换旧值 e.value = value; // 访问后回调 afterNodeAccess(e); // 返回旧值 return oldValue; } } // 结构性修改 ++modCount; // 实际大小大于阈值则扩容 if (++size > threshold) resize(); // 插入后回调 afterNodeInsertion(evict); return null; }
get():数组
public V get(Object key) { Node<K,V> e; return (e = getNode(hash(key), key)) == null ? null : e.value; } final Node<K,V> getNode(int hash, Object key) { Node<K,V>[] tab; Node<K,V> first, e; int n; K k; // table已经初始化,长度大于0,根据hash寻找table中的项也不为空 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<K,V>)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; }
参考网址:多线程
JDK1.8之前:http://www.cnblogs.com/xwdreamer/archive/2012/06/03/2532832.html并发
JDK1.8+:http://www.cnblogs.com/leesf456/p/5242233.html
Dictionary<String, String> dic = new Hashtable<String, String>(); dic.put("zd", "zd"); dic.put("age", "21"); dic.put("zt", "zt"); dic.put("age", "22"); dic.put("sex", "girl"); Enumeration<String> elemvalues = dic.elements(); Enumeration<String> elemkeys = dic.keys(); while(elemvalues.hasMoreElements() && elemkeys.hasMoreElements()){ System.out.print(elemkeys.nextElement()+":"); System.out.println(elemvalues.nextElement()); }
更多详情看源码或戳这里。
LinkedHashMap默认为插入顺序排序,HashMap为无序:
public static void main(String[] args) { // TODO Auto-generated method stub Map<String, String> linkmap = new LinkedHashMap<String, String>(); linkmap.put("zd", "zd"); linkmap.put("age", "21"); linkmap.put("sex", "girl"); linkmap.put("zt", "zt"); linkmap.put("age", "22"); for(Entry<String, String> entry:linkmap.entrySet()){ System.out.println(entry.getKey()+":"+entry.getValue()); } System.out.println("==========================="); Map<String, String> hashmap = new HashMap<String, String>(); hashmap.put("zd", "zd"); hashmap.put("age", "21"); hashmap.put("zt", "zt"); hashmap.put("age", "22"); hashmap.put("sex", "girl"); for(Entry<String, String> entry:hashmap.entrySet()){ System.out.println(entry.getKey()+":"+entry.getValue()); } }
结果展现:
更多详情看源码或者戳这里。
更多详情看源码或者戳这里。
优秀博文:http://www.cnblogs.com/yydcdut/p/3959815.html
红黑树5点规定:
更多详情请戳这里,本人以为讲的很详细,对红黑树也做了详细的阐述。
EnumMap是专门为枚举类型量身定作的Map实现。虽然使用其它的Map实现(如HashMap)也能完成枚举类型实例到值得映射,可是使用EnumMap会更加高效:它只能接收同一枚举类型的实例做为键值,而且因为枚举类型实例的数量相对固定而且有限,因此EnumMap使用数组来存放与枚举类型对应的值。这使得EnumMap的效率很是高。
提示:EnumMap在内部使用枚举类型的ordinal()获得当前实例的声明次序,并使用这个次序维护枚举类型实例对应值在数组的位置。
下面是使用EnumMap的一个代码示例。枚举类型DataBaseType里存放了如今支持的全部数据库类型。针对不一样的数据库,一些数据库相关的方法须要返回不同的值,示例中getURL就是一个。
//现支持的数据库类型枚举类型定义
public enum DataBaseType{ MYSQL,ORACLE,DB2,SQLSERVER }
//DataBaseInfo类中定义的获取数据库URL的方法以及EnumMap的声明。
public class DataBaseInfo{ private EnumMap<DataBaseType, String> urls = new EnumMap<DataBaseType, String>(DataBaseType.class); public DataBaseInfo(){ urls.put(DataBaseType.DB2,"jdbc:db2://localhost:5000/sample"); urls.put(DataBaseType.MYSQL,"jdbc:mysql://localhost/mydb"); urls.put(DataBaseType.ORACLE,"jdbc:oracle:thin:@localhost:1521:sample"); urls.put(DataBaseType.SQLSERVER,"jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=mydb"); } }
/** * 根据不一样的数据库类型,返回对应的URL * @param type DataBaseType枚举类新实例 */ public String getURL(DataBaseType type){ return this.urls.get(type); }
在实际使用中,EnumMap对象urls每每是由外部负责整个应用初始化的代码来填充的。
该博文仅做为复习记录,大多数原理及源码解释已给出连接,优秀博客须要一块儿共赏。最后,如有错误,望纠正。