一 .Map
public interface Map<K,V>
将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。此接口哦取代了Dictionary类,后者完全是一个抽象类,而不是一个接口。
Map接口和Collection接口的区别
- Map是双列的,而Collection是单列的
- Map的键唯一,而Collection的子体系的Set是唯一的
- Map集合的数据结构只针对键有效,跟值无关,而Collection集合的数据结构是针对元素有效
二 .下面先了解Map集合的基本功能,后面研究其常用的四个子类。
添加功能
- V put(K key,V value)
添加元素,也可以有替换功能,如果键是第一次存储,就直接存储元素,返回null。如果键已经存在,那么就用值把以前的值替换掉,返回以前的值
删除功能
-
void clear()
移除所有的键值对元素 -
V remove(Object key)
根据键删除键值对元素,并把值返回
获取功能
-
Set<Map.Entry<K,V>> entrySet()
返回一个键值对的Set集合 -
V get(Object key)
根据键获取值 -
Set keySet():获取集合中所有键的集合
获取集合中所有键的集合 -
Collection values()
获取集合中所有值的集合
判断功能
-
boolean containsKey(Object key)
判断集合是否包含指定的键 -
boolean containsValue(Object value)
判断集合是否包含制定的值 -
boolean isEmpty()
判断集合是否为空
长度功能
- int size()
获取集合中的键值对的对数
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MyTest1 {
public static void main(String[] args) {
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("海绵宝宝",21);
hashMap.put("章鱼哥",22);
hashMap.put("派大星",23);
hashMap.put("蟹老板",24);
//当键已经存在时,再次存储就把旧值替换掉,返回以前的值
Integer integer = hashMap.put("海绵宝宝", 25);
//根据键删除键值对元素
hashMap.remove(21);
//判断集合是否包含指定的键
hashMap.containsKey("派大星");
//判断集合是否包含制定的值
hashMap.containsValue(23);
//返回一个键值对的Set集合
Set entries = hashMap.entrySet();
//根据键获取值
hashMap.get("蟹老板");
//返回集合中所有键的集合
Set strings = hashMap.keySet();
//获取集合中所有值的集合
Collection<Integer> values = hashMap.values();
//获取集合中键值对的对数
int size = hashMap.size();
//清空所有的键值对元素
hashMap.clear();
}
}
三.Map集合的两种遍历方式
方式一
import java.util.HashMap;
import java.util.Set;
public class MyTest2 {
public static void main(String[] args) {
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("海绵宝宝",21);
hashMap.put("章鱼哥",22);
hashMap.put("派大星",23);
hashMap.put("蟹老板",24);
Set<String> set = hashMap.keySet();
for (String key : set) {
System.out.println(key+" "+hashMap.get(key));
}
}
}
方式二
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MyTest3 {
public static void main(String[] args) {
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("海绵宝宝",21);
hashMap.put("章鱼哥",22);
hashMap.put("派大星",23);
hashMap.put("蟹老板",24);
Set<Map.Entry<String, Integer>> entries = hashMap.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+" "+value);
}
}
}
两个的运行结果为:
派大星 23
海绵宝宝 21
章鱼哥 22
蟹老板 24
四.Map接口下面常用的四个子类
- HashMap
- LinkedHashMap
- TreeMap
- ConcurrentHashMap
1.HashMap
- 底层是散列表+红黑树。初始容量为16,加载因子为0.75,每次扩容两倍。
- 允许nul值null键l,存储无序
- 线程非同步
- 散列表容量大于64且链表大于8时,转成红黑树
- key的哈希值会与该值的高16位做异或操作,进一步增加随机性
- 当散列表的元素大于容量 * 加载因子时,会在散列,每次扩容两倍
import java.util.HashMap;
public class MyTest5 {
public static void main(String[] args) {
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("海绵宝宝",21);
hashMap.put("章鱼哥",22);
hashMap.put("派大星",23);
hashMap.put("蟹老板",24);
hashMap.put("蟹老板",999);
System.out.println(hashMap);
}
}
运行结果为:
{派大星=23, 海绵宝宝=21, 章鱼哥=22, 蟹老板=999}
存取顺序不一致
2.LinkedHashMap
- 底层数据结构是散列表+红黑树+双向链表
- 键的数据结构是链表+哈希表,链保证键有序,哈希表保证键唯一
- Map接口的哈希表和链接链表实现,具有可预知的迭代顺序。
- 允许null值null键
- 线程非同步
- 提供插入顺序和访问顺序两种,访问顺序是符合LRU(最近最近未使用算法)的,一般用于扩展(默认是插入排序)。
- 大多使用了HashMap的API,只不过在内部重写了某些方法,维护了双向链表
import java.util.LinkedHashMap;
public class MyTest4 {
public static void main(String[] args) {
LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("郭杰瑞",34);
linkedHashMap.put("角角",24);
linkedHashMap.put("明明",27);
linkedHashMap.put("木鱼水心",32);
linkedHashMap.put("信誓旦旦",37);
System.out.println(linkedHashMap);
}
}
运行结果为:
{郭杰瑞=34, 角角=24, 明明=27, 木鱼水心=32, 信誓旦旦=37}
可以看出存取顺序一致
3.TreeMap
- 底层是红黑树,保证了时间复杂度位log(n)
- 可以对其进行排序,使用Comparable或者Comparator
- 只要compare或者CompareTo认定该元素相等,那就相等
- 线程非同步
- 当自然排序(手动排序)元素不能为null
1.使用自然排序时,要求里面的元素实现了Comparable接口,重写了compareTo()方法。例如下面的一段代码,按照年龄对元素进行排序。
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Student s ) {
int num = this.age - s.getAge();
int num2=num==0?this.name.compareTo(s.name):num;
return num2 ;
}
}
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class MyTest1 {
public static void main(String[] args) {
TreeMap<Student, String> treeMap = new TreeMap<>();
treeMap.put(new Student("章鱼哥",23),"海绵宝宝");
treeMap.put(new Student("熊大",24),"熊出没");
treeMap.put(new Student("叶修",23),"全职高手");
//遍历方式二
Set<Map.Entry<Student, String>> entries = treeMap.entrySet();
for (Map.Entry<Student, String> entry : entries) {
Student key = entry.getKey();
String value = entry.getValue();
System.out.println(key.getAge()+" "+key.getName()+" "+value);
}
}
}
运行结果为:
23 叶修 全职高手
23 章鱼哥 海绵宝宝
24 熊大 熊出没
2.使用比较器排序
public class Student{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class MyTest1 {
public static void main(String[] args) {
TreeMap<Student, String> treeMap = new TreeMap<>();
treeMap.put(new Student("章鱼哥",23),"海绵宝宝");
treeMap.put(new Student("熊大",24),"熊出没");
treeMap.put(new Student("叶修",23),"全职高手");
//遍历方式一
Set<Map.Entry<Student, String>> entries = treeMap.entrySet();
for (Map.Entry<Student, String> entry : entries) {
Student key = entry.getKey();
String value = entry.getValue();
System.out.println(key.getAge()+" "+key.getName()+" "+value);
}
}
}
运行结果为:
23 叶修 全职高手
17 天明 秦时明月
24 熊大 熊出没
23 章鱼哥 海绵宝宝
4.ConcurrentHashMap
- 底层是散列表+红黑树,支持高并发操作
- key和value都不能为空
- 线程是安全的,利用CAS算法和部分操作上锁实现
- get方法是通常是非阻塞,无锁的。重写Node类,通过volatile修饰next来实现每次获取都是最新设置的值
- 在高并发环境下,统计数据(size等)是没有意义的,因为在下一时刻size值就变化了。
五.HashMap和Hashtable的区别
- HashMap:线程不安全,效率高,允许null值null键。
- HashTable:线程安全,效率低,不允许null值null键
六.集合之间的嵌套
- HashMap嵌套HashMap
- HashMap嵌套ArrayList
- ArrayList嵌套HashMap
HashMap嵌套HashMap
import java.util.HashMap;
import java.util.Set;
public class MyTest {
public static void main(String[] args) {
/* 基础班
张三 20
李四 22
就业班
王五 21
赵六 23
*/
//HashMap 嵌套 HashMap
HashMap<String, Integer> jcMap = new HashMap<>();
jcMap.put("张三",20);
jcMap.put("李四",22);
HashMap<String, Integer> jyMap = new HashMap<>();
jyMap.put("王五",21);
jyMap.put("赵六",23);
HashMap<String, HashMap<String, Integer>> maxMap = new HashMap<>();
maxMap.put("基础班",jcMap);
maxMap.put("就业班",jyMap);
Set<String> set = maxMap.keySet();
for (String s : set) {
System.out.println(s);
HashMap<String, Integer> minMap = maxMap.get(s);
Set<String> set1 = minMap.keySet();
for (String s1 : set1) {
System.out.println("\t"+s1+" "+minMap.get(s1));
}
}
}
}
HashMap嵌套ArrayList
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
public class MyTest2 {
public static void main(String[] args) {
/**
*
三国演义
吕布
周瑜
笑傲江湖
令狐冲
林平之
神雕侠侣
郭靖
杨过
*/
// HashMap 嵌套 ArrayList
ArrayList<String> sgList = new ArrayList<>();
sgList.add("吕布");
sgList.add("周瑜");
ArrayList<String> xaList = new ArrayList<>();
xaList.add("令狐冲");
xaList.add("林平之");
ArrayList<String> sdList = new ArrayList<>();
sdList.add("郭靖");
sdList.add("杨过");
HashMap<String, ArrayList<String>> hashMap = new HashMap<>();
hashMap.put("三国演义",sgList);
hashMap.put("笑傲江湖",xaList);
hashMap.put("神雕侠侣",sdList);
Set<String> set = hashMap.keySet();
for (String s : set) {
System.out.println(s);
ArrayList<String> list = hashMap.get(s);
for (String s1 : list) {
System.out.println("\t"+s1);
}
}
}
}
ArrayList嵌套HashMap
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
public class MyTest3 {
public static void main(String[] args) {
//周瑜-- - 小乔
//吕布-- - 貂蝉
//
//郭靖-- - 黄蓉
//杨过-- - 小龙女
//
//令狐冲-- - 任盈盈
//林平之-- - 岳灵珊
//ArrayList 嵌套 HashMap
HashMap<String, String> sgMap = new HashMap<>();
sgMap.put("周瑜","小乔");
sgMap.put("吕布","貂蝉");
HashMap<String, String> sdMap = new HashMap<>();
sdMap.put("郭靖","黄蓉");
sdMap.put("杨过","小龙女");
HashMap<String, String> xaMap = new HashMap<>();
xaMap.put("令狐冲","任盈盈");
xaMap.put("林平之","岳灵珊");
ArrayList<HashMap<String, String>> maxList = new ArrayList<>();
maxList.add(sgMap);
maxList.add(sdMap);
maxList.add(xaMap);
for (HashMap<String, String> map : maxList) {
Set<String> set = map.keySet();
for (String s : set) {
System.out.println(s+"---"+map.get(s));
}
System.out.println();
}
}
}