Javase-day15-Map集合

一、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: 不支持操作异常
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
掌握集合的概念、体系结构、分类及使用场景 2)了解Set接口及主要实现类(HashSet、TreeSet) 3)了解List接口及主要实现类(ArrayList、LinkedList、Vector) 4)了解Map接口及主要实现类(HashMap、TreeMap、HashTable) 二、实验内容及步骤 1、编写程序练习将以下5个Person类的对象放在一个HashSet中。 姓名:张三 身份证号:178880001 姓名:王五 身份证号:178880002 姓名:李四 身份证号:178880003 姓名:王五 身份证号:178880002 姓名:李四 身份证号:178880004 注意:因为Person类是自定义类,需要重写hashCode()方法和equals()方法,并规定只有姓名和身份证号都相等,则对象相等。 其中计算哈希码的算法:(31 + ((name == null) ? 0 : name.hashCode()))*31 + id (注:name:Person对象的姓名,id:Person对象的身份证号) 主方法中作如下测试: 1)创建一个可放置Person类对象的HashSet; 2)依次添加上述5个对象到HashSet中; 3)把集合中的元素打印出来(使用迭代器Iterator) 2、编写程序练习List集合的基本使用: 1) 创建一个只能容纳String对象名为names的ArrayList集合; 2)按顺序往集合中添加5个字符串对象:"张三"、"李四"、"王五"、"马六"、"赵七"; 3)对集合进行遍历,分别打印集合中的每个元素的位置与内容; 4)打印集合的大小,然后删除集合中的第3个元素,并显示删除元素的内容,然后再打印目前集合中第3个元素的内容,并再次打印集合的大小。 3、编写程序练习Map集合的基本使用: 1)创建一个只能容纳String对象的person的HashMap集合; 2)往集合中添加5个"键-值"对象: "id"-"1"; "name"-"张三"; "sex"-"男"; "age"-"25"; "hobby"-"爱学Java" 3)对集合进行遍历,分别打印集合中的每个元素的键与值; 4)打印集合的大小,然后删除集合中的键为age的元素,并显示删除元素的内容,并再次打印集合的大小。 四、思考题 1、集合中的List、Set、Map有哪些不同? 2、为什么使用集合框架,而尽可能少用数组作为存储结构? 3、如何使用TreeSet实现第一题?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值