一、Map集合
回到目录
Map集合是一个接口,接口 Map<K,V>,java.util.Map
Map集合的特点:
- Map集合是一个双列集合,一个元素包含两个值(key、value)
- key和value的数据类型可以相同,也可以不同
- key不允许重复,value可以重复
- key与value是一一对应的关系
举例:
学号 | 姓名 |
---|---|
2020001 | 迪丽热巴 |
2020002 | 古力娜扎 |
2020003 | 玛尔扎哈 |
2020004 | 迪丽热巴 |
二、Map集合常用的实现类
回到目录
创建Map集合对象,可以用多态的写法, 格式类似于:
Map<String, String> map = new HashMap<>();
还可以直接利用实现类自己创建对象:
LinkedHashMap<String, String> map = new LinkedHashMap<>();
- HashMap<K, V>底层是哈希表,查询快。HashSet集合new的就是HashMap集合,但是只是用了其中的K,所以不允许元素重复。
是无序的集合,是多线程的(不同步,速度快)。 - HashMap集合的实现类有LinkedHashMap集合,LinkedHashMap集合底层是哈希表+链表,元素有顺序,是有序的集合。
HashMap和LinkedHashMap,这两个类是Map集合中最常用的实现类。Map集合有的特点,这两个实现类中都有,还都有着各自的特点。
2.1 HashMap<K, V>
java.util.HashMap<K, V> implements Map<K, V>
HashMap集合的特点:
HashMap集合底层是哈希表——查询的速度特别快
JDK1.8之前:数组+单向链表实现
JDK1.8之后:数组+单向链表/红黑树(链表的长度超过8):提高查询的速度
HashMap集合是一个无序的集合,存储元素和取出元素的顺序不相同
2.2 LinkedHashMap<K, V>
java.util.LinkedHashMap<K, V> extends HashMap<K, V>
LinkedHashMap的特点:
- LinkedHashMap集合底层是哈希表+链表(保证迭代的顺序)
- 是一个有序集合,存储元素和取出元素的顺序是一致的
2.3 Hashtable<K, V> — 已经过时了
java.util.Hashtable<K, V> implements Map<K, V>接口,是最早的双列集合。
- Hashtable集合:底层也是哈希表,线程安全,单线程(同步),速度慢。键值对中不可以存储null,一个都不行
- HashMap 集合:底层是哈希表,线程不安全,多线程(不同步),速度快。键值对中都可以为null
Hashtable 和 Vector 集合一样,再JDK1.2之后,就被更加先进的集合(HashMap、ArrayList)取代了,但是Hashtable的子类Properties集合依旧常用,也是唯一一个和IO流相结合的集合。
三、Map接口中常用的方法
1、增改——put(k,v)
- public V put(K key, V value): 把指定的键与指定的值,添加到Map集合中
返回值为V:
存储键值对时,如果key不重复,返回值V是null;如果key重复,会使用新的value替换map中重复的value,并返回被替换的value的值。
// 创建Map集合对象, 多态的写法
Map<String, String> map = new HashMap<>();
// 添加元素
String v1 = map.put("唐三", "小舞1");
System.out.println("v1:" + v1); // 由于没有重复的key, 返回值v1为null
String v2 = map.put("唐三", "小舞2");
System.out.println("v2:" + v2); // 由于key重复了(唐三), 小舞2替换了小舞1, 返回值v2为被替换掉的值: 小舞1
// 控制台输出
System.out.println(map); // Map接口中重写了toString方法,输出的不是地址值: {唐三=小舞2}
// 键key不可以重复, 值value可以重复
2、删——remove(k)
- public V remove(Object key): 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值
返回值V:
key存在, V 返回被删除的值value; key不存在, V 返回null
注意:null可以被赋值给Integer类型,但是不能被赋值给int类型(存在空指针异常),以后要多使用包装类
// 多态创建Map集合对象
Map<String, Integer> Map = new HashMap<>();
// 增
map.put("武庚", 25);
map.put("白菜", 25);
map.put("逆天而行", 35);
System.out.println(map); // {武庚=25, 逆天而行=35, 白菜=25,} 存、取的顺序不一定相同
// 删
Intger v1 = map.remove("逆天而行");
System.out.println("v1: " + v1); // 存在key, 那么v1就是被删除的value: 35
Intger v2 = map.remove("随风起舞"); // 不存在key
System.out.println("v2: " + v2); // v2 : null
// 输出
System.out.println(map) // 存储和取出的顺序不一定相同
3、查——get(k)、containsKey(k)
- public V get(Object key):根据指定的键,在Map集合中获取对应的值
返回值 V :
key存在,返回对应的value值;key不存在,返回null
// get查
Integer v3 = map.get("白菜");
System.out.println(v3); // 25——就是“白菜”对应的value
- boolean containsKey(Object key) : 判断集合中是否包含指定的键
返回值:true,false
boolean b1 = map.containsKey("武庚");
System.out.println(b1) // true
下面两种方法单独拿出来讲:
- public Set keySet() : 获取Map集合中所有的键,存储到Set集合中
- public Set<Map.Entry<K,V>> entrySet() : 获取到Map集合中所有的键值对对象的集合(Set集合)
4、Map集合遍历的方法1—keySet()方法—通过 键 找 值
- 主要步骤:
1、使用Map集合中的方法keySet(),把集合中所有的key取出来,存储到一个Set集合中;
2、遍历set集合【迭代器或者增强for】,获取Map集合中的每一个key;
3、通过Map集合中的get(key),通过key找到value - 主要代码:
Map<String Integer> map = new HashMap<>();
map.put("冯宝宝", 100);
map.put("张楚岚", 23);
map.put("王也", 23);
// 1、使用Map集合中的方法keySet(),把Map集合所有的key取出来,存储到一个Set集合中
Set<String> set = map.keySet();
// 2、遍历set集合,获取Map集合中的每一个key
// 迭代器
Iterator<String> it = set.iterator();
while(it.hasNext()){
String key = it.next();
// 3、Map集合中的方法get(key) , 通过key找到value
Integer value = map.get(key);
sout(key + "=" + value);
}
System.out.println("======我是一条分割线=========");
// 增强for
for(String key : map.keySet){
System.out.println(key + "=" + map.get(key));
}
5、Map集合遍历的方法2—Map.Entry<K, V>更方便获得Map集合的键值对
Map集合中entrySet()方法,返回一个实现Map.Entry接口的对象集合
, 集合中每个对象都是底层Map中一个特定的键/值对, 通过这个集合的迭代器,获得每一个条目(唯一获取方式)的键或值并对值进行更改。Map.Entry中的常用方法有:getKey()得到键;getValue()得到值。
Map.entrySet迭代器会生成EntryIterator,其返回的实例是一个包含key/value键值对的对象。而keySet中迭代器返回的只是key对象,还需要到map中二次取值。故entrySet()方法要比keySet()方法快一倍左右。
- Set<Map.Entry<K, V>> entrySet():获取所有键值对对象的集合
- 用增强for(或迭代器)来遍历键值对对象的集合,得到每一个键值对对象Map.Entry
- 根据键值对对象获取键和值:用 getKey()得到键,用getValue()得到值
Map<String, String> map = new HashMap<>();
// 添加元素
map.put("唐三","小五");
map.put("武庚","白菜");
map.put("A","a");
// 获取所有键值对对象的集合
Set<Map.Entry<String, String>> entrySet = map.entrySet();
// 迭代器遍历
Iterator<Map.Entry<String, String>> it = entrySet.iterator();
while(it.hasNext()){
// 得到键值对对象
Map.Entry<String, String> entry = it.next();
// 根据键值对对象获取键和值
String key0 = entry.getKey();
String value0 = entry.getValue().
System.out.println(key + ", " + value);
}
// 用增强for来遍历键值对对象的集合,得到每一个键值对对象
for(Map.Entry<String, String> me : entrySet) {
// 根据键值对对象获取键和值
String key = me.getKey();
String value = me.getValue();
System.out.println(key + ", " + value);
}
四、HashMap集合存储自定义类型的键值
回到目录
如果使用了自定义的类型作为键key,要再自定义的类中重写hashCode方法和equals方法(idea自动生成),以保证键唯一
- 需求:创建一个HashMap集合,键是学号(String),值是学生对象(Student)。存储三个键值对,并遍历
- 思路:定义学生类;创建HashMap集合对象;创建学生对象;把学生添加到集合;遍历集合(键找值,或者,键值对对象找键和值)
// Student类的定义省了
// 创建HashMap集合对象
HashMap<String, Student> hm = new HashMap<>();
// 创建学生对象
Student s1 = new Student("迪丽热巴", 30);
Student s2 = new Student("古力娜扎", 31);
Student s3 = new Student("玛尔扎哈", 100);
// 把学生添加到集合
hm.put("haha01", s1);
hm.put("haha02", s2);
hm.put("haha03", s3);
// 遍历方式1:键找值 (key是String类)
Set<String> keyset = hm.keySet();
for(String key : keyset) {
Student value = hm.get(key);
System.out.println(key + ", "+ value.getName() + ", " + value.getAge());
}
// 遍历方式2:键值对对象找键和值
Set<Map.Entry<String, Student>> entrySet = hm.entrySet();
for(Map.Entry<String, Student> me : entrySet) {
String key = me.getKey();
Student value = me.getValue();
System.out.println(key + ", "+ value.getName() + ", " + value.getAge());
}
五、LinkedHashMap集合
- LinkedHashMap集合继承自HashMap集合,底层原理:哈希表+链表(记录元素顺序)
- LinkedHashMap对象的创建:
LinkedHashMap<String, String> linked = new LinkedHashMap<>();
存键的顺序是a,c,b,那么控制台输出的顺序就是a,c,b
六、JDK9的新特性
回到目录
JDK9的新特性:
List接口、Set接口、Map接口:里边增加了一个【静态的方法of】,可以给集合一次性添加多个元素。
static List of(E… elements)
使用前提:
集合中存储的元素的个数已经确定了,不能再改变
注意:
- of方法只适用于List接口,Set接口,Map接口,不适用于接接口的实现类
- of方法的返回值是一个不能改变的集合,集合不能再使用add,put方法添加元素,会抛出异常
- Set接口和Map接口在调用of方法的时候,不能有重复的元素,否则会抛出异常
List<String> list = List.of("a", "b", "a", "c", "d");
System.out.println(list); // [a, b, a, c, d]
// list.add("w"); //UnsupportedOperationException: 不支持操作异常
// Set<String> set = Set.of("a", "b", "a", "c", "d"); // IllegalArgumentException: 非法参数异常,有重复的元素
Set<String> set = Set.of("a", "b", "c", "d");
// set.add("w"); // UnsupportedOperationException:不支持操作异常
// Map<String, Integer> map = Map.of("张三", 18, "李四", 19, "王五", 20,"张三",19);
// IllegalArgumentException: 非法参数异常,有重复的元素
Map<String, Integer> map = Map.of("张三", 18, "李四", 19, "王五", 20);
System.out.println(map); // {王五=20, 李四=19, 张三=18}
// map.put("赵四",30); // UnsupportedOperationException: 不支持操作异常