(1)Map 与 Collection 并列存在。用于保存具有映射关系的数据:Key-Value。
(2)Map 中的 key 和 value 可以是任何引用类型的数据,会封装到 HashMaps$Node 对象中。
(3)Map 中的 key 不允许重复,原因和Hashset一样。
(4)Map 中的 value 可以重复。
(5)Map 的 key 可以为 null,value 也可以为 null。注意 key 为null,只能有一个。
(6)key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到对应的 value。
(7)Map 存放数据的 key-value 示意图,一对 K-V 是放在一个 HashMap的Node 中的,又因为 Node 实现了 Entry 接口,有些书上也说一对 K-V 就是一个Entry(如图)。
public class Demo {
public static void main(String[] args) {
HashMap map = new HashMap();
map.put("name","Tom");
Set entrySet = map.entrySet(); // Set<Map.Entry<K,V>>
Set keySet = map.keySet(); // Set<K>
Collection values = map.values(); //Collection<V>
}
}
解读:
(1)为了方便程序员的遍历,会创建EntrySet集合。
即:transient Set<Map.Entry<K,V>> entrySet;
(2)entrySet中,定义的类型是 Map.Entry,但是实际上存放的还是 HashMap$Node
即:static class Node<K,V> implements Map.Entry<K,V>
(3)Map.Entry提供了两个重要方法
K getKey();
V getValue();
(1)put:添加
(2)remove:根据键删除映射关系
(3)get:根据键获取值
(4)size:获取元素个数
(5)isEmpty:判断个数是否为0
(6)clear:清除
(7)containskey:查找键是否存在
public class Demo {
public static void main(String[] args) {
HashMap map = new HashMap();
map.put("name","Tom");
map.put("age",12);
Set keySet = map.keySet();
// (1) 增强for
for (Object key : keySet) {
System.out.println(key + "-" + map.get(key));
}
// (2) 迭代器
Iterator it = keySet.iterator();
while (it.hasNext()) {
Object key = it.next();
System.out.println(key + "-" + map.get(key));
}
}
}
public class Demo {
public static void main(String[] args) {
HashMap map = new HashMap();
map.put("name", "Tom");
map.put("age", 12);
Collection values = map.values();
// (1) 增强for
for (Object value : values) {
System.out.println(value);
}
// (2) 迭代器
Iterator it = values.iterator();
while (it.hasNext()) {
Object value = it.next();
System.out.println(value);
}
}
}
public class Demo {
public static void main(String[] args) {
HashMap map = new HashMap();
map.put("name", "Tom");
map.put("age", 12);
Set entrySet = map.entrySet();
// (1) 增强for
for (Object entry : entrySet) {
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey() + "-" + m.getValue());
}
// (2) 迭代器
Iterator it = entrySet.iterator();
while (it.hasNext()) {
Object entry = it.next();
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey() + "-" + m.getValue());
}
}
}
(1)HashMap 底层维护了 Node 类型的数组 table,默认为 null。
(2)当创建对象时,将加载因子(loadfactor)初始化为0.75。
(3)当添加 key-val 时,通过 key 的哈希值得到在 table 的索引。然后判断该索引处是否有元素,如果没有元素直接添加。如果该索引处有元素,继续判断该元素的 key 和准备加入的key 是否相等,如果相等,则直接替换 val ;如果不相等需要判断是树结构还是链表结构,做出相应处理。如果添加时发现容量不够,则需要扩容。
(4)第1次添加,则需要扩容table容量为16,临界值(threshold)为12。
(5)以后再扩容,则需要扩容 table 容量为原来的2倍,临界值为原来的2倍,即24,依次类推。
(6)在 Java8 中,如果一条链表的元素个数超过 TREEIFY_THRESHOLD(默认是8),并且 table 的大小 >= MIN_TREEIFY_CAPACITY(默认64)就会进行树化(红黑树)。
(1)存放的元素是键值对:即K-V。
(2)Hashtable 的 键和值都不能为 null,否则会抛出空指针异常。
(3)Hashtable 是线程安全的(synchronized),HashMap 是线程不安全的。
(1)底层有数组 Hashtable$Entry[] ,初始化大小为11
(2)if (count>=threshold)满足时,就进行扩容。
按照 int newCapacity=(oldcapacity<<1)+1;的大小扩容。
(1)Properties 类继承自 Hashtable 类井且实现了 Map 接口,也是使用一种键值对的形式来保存数据。
(2)Properties 还主要用于 xxx.properties 文件中,加载数据到 Propertie s类对象,并进行读取和修改。