目录
Map接口的架构
Map 接口:双列集合,用来存储一对(key - value)的数据(映射)
HashMap:作为 Map 的主要实现类,线程不安全但效率高。可以储存 null 的 key 和 value
LinkedHashMap:保证在遍历 map 元素时,可以按照添加的顺序实现遍历。 LinkedHashMap 在原有的 HashMap 底层结构基础上,添加了一对 指针,指向前一个和后一个元素。对于频繁的遍历操作,此类执行 效率高于 HashMap
TreeMap:保证按照添加的 key - value 对进行排序,实现排序遍历。此时考虑 key 的自然排 序或定制排序
Hashtable:作为 Map 接口古老的实现类,线程安全但效率低。不能存储 null 的 key 和 value
Properties:常用来处理配置文件。key 和 value 都是 String 类型
Map结构的理解
1. Map 中的 key:无序的、不可重复的,使用 Set 存储所有的 key。其中 key 所在的类要重写 equals()和 hashCode()(以 HashMap 为例)
2. Map 中的 value:无序的,可重复的,使用 Collection 存储所有的 value。其中 value 所在类要 重写 equals()
3. 一个键值对 key - value 构成了一个 Entry 对象
4. Map 中的 Entry:无序的、不可重复的,使用 Set 存储所有的 Entry
Map接口的底层实现原理
HashMap的底层实现原理
JDK 7.0 及之前
HashMap map = new HashMap ( );
在实例化以后,底层创建了长度是 16 的一维数组 Entry [ ] table
在不断添加数据的过程中,会涉及到扩容的问题,当超出临界值(且要存放的位置非空)时,扩容。默认的扩容方式:扩容为原来容量的 2 倍,并将原有的数据复制过来
map . put (key1 , value1);
首先,调用 key1 所在类的 hashCode()计算 key1 的哈希值,此哈希值经过某种算法计算以后,得到在 Entry 数组中的存放位置
如果此位置上的数组为空,此时的 key1 - value1 添加成功
如果此位置上的数组不为空,(意味着此位置上存在一个或多个数据(以链表的形式存 在)),比较 key1 和已经存在的一个或多个数据的哈希值
如果 key1 的哈希值与已经存在的数据的哈希值都不同,此时 key1 - value1 添加成功
如果 key1 的哈希值与已经存在的某一个数据(key2 - value2)的哈希值相同,比较 key1 所在类的 equals(key2)
如果 equals()返回 false,此时 key1 - value1添加成功
如果 equals()返回 true,此时使用 value1 替换 value2
关于添加成功的后两种情况,此时的 key1 - value1 和原来的数据以链表方式存储
JDK 8.0 及之后
相较于 JDK 7.0 底层实现方面的不同
1. new HashMap ( ):底层没有创建一个长度为 16 的数组
2. JDK 8.0 底层的数组是 Node [ ] ,而非 Entry [ ]
3. 首次调用 put()方法时,底层创建长度为 16 的数组
4. JDK 7.0 底层结构只有数组 + 链表,JDK 8.0 中底层结构为数组 + 链表 + 红黑树
当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8 且当前数组的长度 > 64 ,此 时此索引位置上的所有数据改为使用红黑树存储
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
public class HashMapTest {
@Test
public void test(){
Map map = new HashMap();
map.put("AA",123);
map.put(45,1234);
map.put("CC",56);
System.out.println(map);
}
}
>>> {AA=123, CC=56, 45=1234}
HashMap源码中需要了解的常量
DEFAULT_INITIAL_CAPACITY:HashMap 的默认容量,16
DEFAULT_LOAD_FACTOR:HashMap 的默认加载因子,0.75
threshold:扩容的临界值,容量 * 填充因子,16 * 0.75 = 12
TREEIFY_THRESHOLD:Bucket 中链表长度大于该默认值,转化为红黑树,8
MIN_TREEIFY_CAPACITY:桶中的 Node 被树化时最小的 hash 表容量,64
LinkedHashMap的底层实现原理
static class Entry <K, V> extends HashMap . Node <K, V> {
Entry <K, V> before, after; // 能够记录添加的元素的先后顺序
Entry (int hash, K key, V value, Node <K, V> next) {
super (hash, key, value, next);
}
}
import org.junit.Test;
import java.util.LinkedHashMap;
import java.util.Map;
public class MapTest {
@Test
public void test(){
Map map = new LinkedHashMap();
map.put("AA",123);
map.put(45,1234);
map.put("CC",56);
System.out.println(map);
}
}
>>> {AA=123, 45=1234, CC=56}
Map接口的常用方法
添加、删除、修改 | Object put(Object key,Object value) | 将指定 key - value 添加到(或修改)当前 map 对象中 |
void putAll(Map m) | 将 m 中的所有 key - value 对存放到当前 map 中 | |
Object remove(Object key) | 移除指定 key 的 key - value 对,并返回 value | |
void clear() | 清空当前 map 中的所有数据 | |
元素查询的操作 | Object get(Object key) | 获取指定 key 对应的 value |
boolean containsKey(Object key) | 是否包含指定的 key | |
boolean containsValue(Object value) | 是否包含指定的 value | |
int size() | 返回 map 中 key - value 对的个数 | |
boolean isEmpty() | 判断当前 map 是否为空 | |
boolean equals(Object obj) | 判断当前 map 和参数对象 obj 是否相等 | |
元视图操作的方法 | Set keySet() | 返回所有 key 构成的 Set 集合 |
Collection values() | 返回所有 value 构成的 Collection 集合 | |
Set entrySet() | 返回所有 key - value 对构成的 Set 集合 |
import org.junit.Test;
import java.util.*;
public class MapTest {
@Test
public void test(){
Map map = new HashMap();
map.put("AA",123);
map.put(45,1234);
map.put("CC",56);
//putAll()
Map map1 = new HashMap();
map1.put("BB",123);
map1.put("DD",567);
map.putAll(map1);
System.out.println("putAll():" + map);
//remove()
Object value = map.remove("CC");
System.out.println("remove():" + map);
//get()
System.out.println("get():" + map.get(45));
//containsKey()
boolean isExist = map.containsKey("BB");
System.out.println("containsKey():" + isExist);
//keySet()
Set set = map.keySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//values()
Collection values = map.values();
for (Object obj : values){
System.out.println(obj);
}
//entrySet()
Set entrySet = map.entrySet();
Iterator iterator1 = entrySet.iterator();
while (iterator1.hasNext()){
Object obj = iterator1.next();
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey() + "---->" + entry.getValue());
}
//clear
map.clear();
}
}
>>> putAll():{AA=123, CC=56, BB=123, DD=567, 45=1234}
remove():{AA=123, BB=123, DD=567, 45=1234}
get():1234
containsKey():true
AA
BB
DD
45
123
123
567
1234
AA---->123
BB---->123
DD---->567
45---->1234
TreeMap的使用
向 TreeMap 中添加 key - value,要求 key 必须是由同一个类创建的对象
要按照 key 进行排序,分为:自然排序和定制排序
使用原理与 TreeSet 相同,详细请见下面文章中 TreeSet 的使用方法,如何重写 compareTo()与 compare()
Collection子接口:Set接口:https://blog.csdn.net/lijibai_/article/details/124060677
Properties的使用
Properties 类是 Hashtable 的子类,该类对象用于处理属性文件
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class PropertiesTest {
public static void main(String[] args) throws IOException {
Properties pros = new Properties();
FileInputStream fis = new FileInputStream("db.properties");
pros.load(fis);
String name = pros.getProperty("name");
String password = pros.getProperty("password");
System.out.println("name = " + name + "," + "password = " + password);
}
}