输出结果如下
-----------第一种方式----------- aa-11 bb-22 cc-33 dd-44 ee-55 -----------第二种方式----------- aa-11 bb-22 cc-33 dd-44 ee-55 ----取出所有的value 使用增强for---- 11 22 33 44 55 ----取出所有的value 使用迭代器---- 11 22 33 44 55 -----使用EntrySet 的 增强for循环(第三种)----- aa-11 bb-22 cc-33 dd-44 ee-55 -----使用EntrySet 的 增强for循环(第4种)----- aa-11 bb-22 cc-33 dd-44 ee-55
HashMap小结
下面是HashMap底层机制和源码剖析
具体源码分析如下
public class HashMapSource1 { public static void main(String[] args) { HashMap map = new HashMap(); map.put("java", 10); map.put("php", 10); map.put("java", 20); System.out.println("map=" + map); //解读HashMap源码 //1.执行构造器new HashMap() //初始化加载因子loadFactor=0.75 //HashMap$Node[] table=null /* //2.执行put 调用hash方法,计算key的hash值(h = key.hashCode()) ^ (h >>> 16) public V put(K key, V value) {k="java",v=10 return putVal(hash(key), key, value, false, true); } 3.执行putVal 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数组为空,或者length=0,就扩容到16 if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; //取出hash值对应的table的索引位置的Node,如果为null,就直接把加入的k-v //创建成一个Node,加入该位置即可 if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k;//辅助变量 //如果table的索引位置的key的hash值和新的key的hash值相同, //并且满足(现有的结点的key和准备添加的key是同一个对象||equals返回真) //就认为不能加入新的k-v if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode)//如果当前的table的已有的Node,是红黑树,就按照红黑树的方式处理 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); //加入后判断当前链表的数目 是否已经到达8个,到8个后,就调用treeifyBin //进行红黑树的转换 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash &&//如果在循环条件过程中,发现有相同,就break,就只是替换value ((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;//替换,key对应的值 afterNodeAccess(e); return oldValue; } } ++modCount;//每增加一个Node,就size++ if (++size > threshold)//如果size大于临界值就扩容 resize(); afterNodeInsertion(evict); return null; } 5.关于树化(转成红黑树) //如果table为null,或者大小还没有到64,暂时不树化,而是进行扩容 //否则才会真正的树化 if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) resize(); */ } }
Hashtable底层源码分析如下
Hashtable分析源码如下
@SuppressWarnings({"all"}) public class HashTableExercise { public static void main(String[] args) { Hashtable table = new Hashtable(); // table.put(null, 100);//异常 NullPointerException // table.put("john", null);//异常 NullPointerException table.put("john", 100);//ok table.put("lucy", 100);//ok table.put("lic", 100);//ok table.put("lic", 88);//ok table.put("hello1", 1); table.put("hello2", 2); table.put("hello3", 3); table.put("hello4", 4); table.put("hello5", 5); table.put("hello6", 6); table.put("hello7", 7); System.out.println(table); //简单说明一下 Hashtable的底层 //1.底层有数组Hashtable$Entry[] 初始化为11 //2、临界值 threshold 8 =11*0.75 //3、扩容:按照自己的扩容机制来进行即可 //4、执行方法 addEntry(hash, key, value, index); 添加K-V 封装到Entry //5、当if(count>=threshold)满足时,就进行扩容 //6、 int newCapacity = (oldCapacity << 1) + 1; 扩容到原来的2倍+1 } }
下面是HashMap和Hashtable的一个对比
Properties类的详解
对应的代码如下
package com.map_; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.Properties; /** * @author ly * @version 1.0 */ public class Properties_ { public static void main(String[] args) { //1.Properties 继承了 Hashtable //2.可以通过k-v 存放数据,当然key 和 value不能为null Properties properties = new Properties(); // properties.put(null, 100);//抛出空指针异常 // properties.put("abc", null);// 抛出空指针异常 properties.put("john", 100);//k-v properties.put("lucy", 100);//k-v properties.put("lic", 100);//k-v properties.put("lic", 88);//k-v 如果有相同的key,value被替换 System.out.println("properties=" + properties); //通过k,获取对应的值 System.out.println(properties.get("lic"));//88 //删除 properties.remove("lic"); System.out.println("properties=" + properties); //修改 properties.put("john", "约翰"); System.out.println("properties=" + properties); } }
输出结果如下
properties={john=100, lic=88, lucy=100} 88 properties={john=100, lucy=100} properties={john=约翰, lucy=100}
总结
TreeMap类的详解,并且可以实现key的排序
public class TreeMap_ { public static void main(String[] args) { //使用默认的构造器,创建TreeMap,是无序的(也没有排序) /* 要求:按照传入的key的字符串的大小进行排序 */ // TreeMap treeMap = new TreeMap(); TreeMap treeMap = new TreeMap(new Comparator() { @Override public int compare(Object o1, Object o2) { //按照传入的key的字符串的大小进行排序 ,从小到大排序 // return ((String) o1).compareTo((String) o2); //按照传入的key的字符串的大小进行排序 ,从大到小排序 // return ((String) o1).compareTo((String) o2); //按照key的字符串的长度 从小到大排序 return ((String) o1).length() - ((String) o2).length(); } }); treeMap.put("jack", "杰克"); treeMap.put("tom", "汤姆"); treeMap.put("kristina", "克瑞斯提诺"); treeMap.put("smith", "史密斯"); System.out.println(treeMap); //解读源码 /* 1.构造器,把传入的实现了Comparator接口的匿名内部类(对象),传给了TreeMap的comparator public TreeMap(Comparator<? super K> comparator) { this.comparator = comparator; } 2.调用put方法 2.1第一次添加,把k-v封装到Entry对象,放入到root Entry<K,V> t = root; if (t == null) { compare(key, key); // type (and possibly null) check root = new Entry<>(key, value, null); size = 1; modCount++; return null; } 2.2以后添加 Comparator<? super K> cpr = comparator; if (cpr != null) { do { parent = t; cmp = cpr.compare(key, t.key);//动态绑定到我们的匿名内部类的compare if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else //如果我们遍历过程中,发现准备添加的key,和当前已有的key相等,就不添加 return t.setValue(value); } while (t != null); } */ } }
输出结果如下
{tom=汤姆, jack=杰克, smith=史密斯, kristina=克瑞斯提诺}