day17
-
Map集合
1.1 Map集合的概述 -
Map集合 : 双列集合的顶层接口, 来自于java.util包
map 在英文中表示地图的含义, 地图上的每一个点都与现实生活中的一个地理位置一一对应的关系 -
Map集合的描述:
Map<K,V> : Map集合中,带有两个泛型,者两个泛型,都是引用数据类型.
K----->Key---->键
V----->Value---->值
因此Map集合中存储的一对元素,称为键值对映射关系,是一对一的关系
-
Map集合的特点
Map集合中,Key值唯一(整个Map集合中Key值不能重复)的,Value值不唯一(整个Map中value的值彼此是可以重复的)
通常情况下,都是使用唯一的Key值映射寻找不唯一的Value值
1.2 Map集合的常用方法
Map是一个接口,不能实例化对象,于是,需要一个实现类,HashMap
HashMap来自java.util包
// 接口的多态性, 父接口的引用指向一个实现类对象
Map<K,V> map = new HashMap();
- put(K key,V value): 表示将key与value的键值对映射关系对象,添加到map集合中
- 当通过put方法,向Map中添加不存在的key值,直接添加成功
- 当通过put方法,向Map中添加已经存在的key值,相当于修改,将后添加的value值,替换掉原有的key值对应的value值
- remove(K key) : 将Map集合中的指定key值的键值对映射关系对象删除掉,返回值类型V—>value,返回所删除的键值对中的value值
- clear() : 表示清空Map集合,将集合中所有的键值对映射关系对象删除,Map集合仍然存在
- isEmpty() : 判断Map集合中,是否还有键值对映射关系对象,如果没有,返回true,如果有,返回false, 方法的返回值类型boolean
- containsKey(Object key) : 判断Map集合中,是否包含指定的key值,包含,返回true,不包含,返回false.返回值类型boolean
- containsValue(Object value) : 判断Map集合中,是否包含指定的value值,包含,返回true,不包含,返回false.返回值类型boolean
- get(Object key) : 通过Map集合中的key的值,获取到对应的value值,返回值类型就是value值
- size() : 求Map集合中的键值对映射关系数量,返回值类型int类型
代码
package com.zgjy.mapDemo;
import java.util.HashMap;
import java.util.Map;
public class MapMethod {
public static void main(String[] args) {
// Map集合存储的K和V的值,都必须是引用数据类型
/*Map<Integer, String> map = new HashMap<Integer, String>();
putMethod(map);
System.out.println("----"+map);// {1=a, 2=hello, 3=c}
removeMethod(map);
clearMethod(map);*/
containsMethod();
}
// 1. 向map集合中添加键值对元素,是用put方法
public static void putMethod(Map<Integer, String> map) {
// 1. 当通过put方法,向Map中添加不存在的key值,直接添加成功
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
System.out.println(map);//{1=a, 2=b, 3=c}
// map集合中key是不重复的,map集合中的key值,就相当于set集合
// 2. 当通过put方法,向Map中添加已经存在的key值,相当于修改
// 将后添加的value值,替换掉原有的key值对应的value值
map.put(2, "hello");
System.out.println(map);// {1=a, 2=hello, 3=c}
}
// 2. remove(K key) : 返回值类型,V--->value,返回所删除的键值对中的value值
public static void removeMethod(Map<Integer, String> map) {
String value = map.remove(1);
System.out.println(value);// a
System.out.println(map);// {2=hello, 3=c}
}
// 3. clear():表示清空Map集合,将集合中所有的键值对映射关系对象删除,Map集合仍然存在
public static void clearMethod(Map<Integer, String> map) {
System.out.println(map.isEmpty());// false
map.clear();
System.out.println(map);//{}
// 4. isEmpty(): 判断Map集合中,是否还有键值对映射关系对象,如果没有,返回true,如果有,返回false
System.out.println(map.isEmpty());// true
}
// 5.containsKey: 判断Map集合中,是否包含指定的key值,包含,返回true,不包含,返回false.返回值类型boolean
// containsValue:判断Map集合中,是否包含指定的value值,包含,返回true,不包含,返回false.返回值类型boolean
public static void containsMethod() {
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(11, "a");
map.put(22, "b");
map.put(33, "c");
System.out.println(map.containsKey(33));// true
System.out.println(map.containsKey(3));//false
System.out.println(map.containsValue("a"));// true
System.out.println(map.containsValue("A"));//false
// 6. get(Object key):通过Map集合中的key的值,获取到对应的value值,返回值类型就是value值
String value = map.get(11);
System.out.println(value);//a
// 7. size() : 求Map集合中的键值对映射关系数量,返回值类型int类型
System.out.println(map.size());// 3
}
}
1.3 Map集合的遍历
将Map集合中的元素,一个一个获取到
1.3.1 Map集合的第一种遍历KeySet
keySet() : 在Map集合中的方法
功能 : 将Map集合中的所有的key值获取到,将所有Key放置在一个Set集合中
代码
package com.zgjy.mapDemo;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapBianLi {
public static void main(String[] args) {
bianLi1();
}
public static void bianLi1() {
// 1. 创建一个Map集合
Map<Integer, String> map = new HashMap<Integer, String>();
// 2. 向Map集合中添加元素
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
// 3. 通过keySet方法,获取到Map集合中的所有的key值
Set<Integer> set = map.keySet();
// 4. 将所有的key值获取到,通过key值获取到对应的value值
for(Integer key : set) {
// 5. 通过get(Object key)方法获取value值
String value = map.get(key);
System.out.println(key+"----"+value);
}
// 6. 使用迭代器遍历Set集合
// 1) 先获取到Set集合的迭代器对象 iterator()
Iterator<Integer> it = set.iterator();
while(it.hasNext()) {
// 获取到集合中的key值
Integer key = it.next();
// 通过key的值,获取到value值
String value = map.get(key);
System.out.println(key+"+++++"+value);
}
}
}
1.3.2 Map集合第二种遍历EntrySet
- entrySet() : 将Map集合中的键值对映射关系对象,获取到,放置到一个Set集合中,方法返回值类型Set集合,返回的Set集合中泛型为Map.Entry<Integer,String>
- 键值对映射关系对象 : 使用Map.Entry<K,V>表示,在Map接口中,有一个静态的内部接口Entry<K,V>, Entry<K,V>就表示Map中的每一对元素,因为Entry定义在Map内部,因此使用时,需要外部接口.内部接口的方式调用,即Map.Entry<K,V>
- 获取到Set集合所包含的映射关系对象后,遍历Set集合,将每一对键值对获取到,通过Entry中的方法getkey(),获取到映射关系中的key值; getValue()获取到映射关系中的value值
代码
package com.zgjy.mapDemo;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapBianLi {
public static void main(String[] args) {
bianLi2();
bianLi3();
}
// 2. entrySet() Map集合的遍历
public static void bianLi2() {
// 1. 创建一个Map集合
Map<Integer, String> map = new HashMap<Integer, String>();
// 2. 向Map集合中添加元素
map.put(11, "a");
map.put(22, "b");
map.put(33, "c");
// 3. 使用entrySet()方法,获取到Map集合中的而所有的键值对映射关系
// 每一个键值对对象关系,都是一个Map.Entry<Integer,String>类型
Set<Map.Entry<Integer, String>> set = map.entrySet();
// 4.使用增强for遍历这个set集合,将每一对键值关系获取到
for(Map.Entry<Integer, String> entry : set) {
// 5. 通过entry中方法
// getKey() : 将键值对关系中的key值获取到
Integer key = entry.getKey();
// getValue() : 将键值对关系中的value值获取到
String value = entry.getValue();
System.out.println(key+"??????"+value);
}
}
// 3. 使用迭代器和entrySet进行Map集合的遍历
public static void bianLi3() {
// 1. 创建一个Map集合
Map<Integer, String> map = new HashMap<Integer, String>();
// 2. 向Map集合中添加元素
map.put(11, “a”);
map.put(22, “b”);
map.put(33, “c”);
// 3. 使用entrySet获取到Map集合中的所有键值对
Set<Map.Entry<Integer, String>> set = map.entrySet();
// 4. 使用迭代器进行set集合的遍历
Iterator<Map.Entry<Integer, String>> it = set.iterator();
// 5. 循环将每一个键值对关系获取到
while(it.hasNext()) {
Map.Entry<Integer, String> entry = it.next();
// 6. getKey
//getValue
System.out.println(entry.getKey()+"*****"+entry.getValue());
}
}
}
练习
定义一个字符串 : aaaabbccddd!@#@KaTeX parse error: Expected 'EOF', got '#' at position 2: @#̲%cc66ff
统计字符串中每个字符出现的次数
例如 : a有4个, b有2个,c有4个,d有3个,!有1个,@有3个,$有2个,%有1个,6有2个,f有2个
分析:
- 拥有的字符串-----> 获取到字符串中的内一个字符—>String---->
toCharArray()-----> 将字符串中的每一个字符获取到,将所有字符放置到一个char[] - 结果 a—4 b----2 c----3 属于键值对关系,最终结果使用Map集合承装
字符–>key 数量—value - 数字符出现的次数 :
Map<Character,Integer> map
- 遍历char[],获取到每一个字符
- 判断,这个字符在map中是否存在
不存在, 证明字符第一次计数, put(字符,1)
存在,在原有的计数(get(字符)---->字符对应的计数)的基础上+1
代码
package com.zgjy.mapDemo;
import java.util.HashMap;
import java.util.Map;
public class MapLianXi {
public static void main(String[] args) {
// 1. 定义一个字符串
String s = “aaaabbccddd!@#@KaTeX parse error: Expected 'EOF', got '#' at position 2: @#̲%cc66ffHello”;
// 2. 将字符串转换成字符数组
char[] ch = s.toCharArray();
// 3. 准备一个Map集合
Map<Character, Integer> map = new HashMap<Character, Integer>();
// 4. 将字符数组中的每一个字符获取到,循环
for(int i = 0 ; i < ch.length ; i ++) {
// 5. 判断字符在map集合中是否存在
if(map.containsKey(ch[i])) {// 结果为true,证明字符已经存在过
// 获取到当前字符在map集合中的计数
Integer count = map.get(ch[i]);
map.put(ch[i], count+1);
}else {// 结果为false,证明字符第一次存储在map集合中.将字符计数设置为1
map.put(ch[i], 1);
}
}
System.out.println(map);
}
}
1.4 HashMap的Key值保证元素唯一
- HashMap是Map接口的实现类,来自java.util包,也是带有两个泛型
HashMap<K,V> - HashMap如果存储的是JDK定义好的引用数据类型,key的值保持唯一
- HashMap如果存储的是自定义的引用数据类型,如果需要将自定类型通过成员变量的值进行去重复,那么需要重写hashCode和equals, 原因 : HashMap中的key的值,去重复原理与HashSet原理完全你一致
要求: 定义一个person类,类中属性姓名,年龄,要求相同的姓名和年龄认为是重复的Person数据
代码
package com.zgjy.mapDemo;
import java.util.HashMap;
public class MapOnly {
public static void main(String[] args) {
// 1. 创建一个Map集合
HashMap<Person, String> map = new HashMap<>();
map.put(new Person("张三" , 20), "a");
map.put(new Person("李四" , 25), "a");
map.put(new Person("张三" , 20), "b");
System.out.println(map);
}
}
package com.zgjy.mapDemo;
public class Person {
private String name;
private int 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;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return “Person [name=” + name + “, age=” + age + “]”;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
1.5 LinkedHashMap
LinkedHashMap是HashMap的子类
HashMap 的key的值,与HashSet原理一致,因此在HashMap中存储的元素,无序的
LinkedHashMap与HashMap的区别就是能够让元素的存取有序的
代码
package com.zgjy.mapDemo;
import java.util.HashMap;
import java.util.LinkedHashMap;
public class MapOnly {
public static void main(String[] args) {
// 1. 创建一个Map集合
HashMap<Person, String> map = new HashMap<>();
map.put(new Person("张三" , 20), "a");
map.put(new Person("李四" , 25), "a");
map.put(new Person("张三" , 20), "b");
//{Person [name=李四, age=25]=a, Person [name=张三, age=20]=b}
System.out.println(map);
// 2. 使用LinkedHashMap进行元素有序存储
LinkedHashMap<Person, String> lhm = new LinkedHashMap<>();
lhm.put(new Person("张三" , 20), "a");
lhm.put(new Person("李四" , 25), "a");
lhm.put(new Person("张三" , 20), "b");
//{Person [name=张三, age=20]=b, Person [name=李四, age=25]=a}
System.out.println(lhm);
}
}
1.6 HashMap与Hashtable的区别
HashMap 与 Hashtable 都是Map接口的实现类,都是用于键值对映射关系的存储
所有的引用数据类型的默认值都可以设置为null ,null在堆内存中什么都没有
区别:
- Hashtable 从JDK1.0 开始 , HashMap 从JDK1.2版本开始
- Hashtable线程安全,运行速度慢 ; HashMap 线程不安全,运行速度快
- Hashtable 不支持存储null的键或者值
HashMap 支持存储null的键或者值
代码
package com.zgjy.mapDemo;
import java.util.HashMap;
import java.util.Hashtable;
public class HashtableDemo {
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<>();
map.put(null, "a");
map.put(1, null);
map.put(2, "b");
System.out.println("----"+map);
Hashtable<Integer, String> table = new Hashtable<>();
table.put(null, "a");
table.put(1, null);
table.put(2, "b");
System.out.println(table);
}
}
-
Collections工具类
Arrays 工具类 : 功能 ,针对于数组做一些操作
Collections 工具类 : 功能,针对于集合进行一些操作, 来自于java.util包,所有方法都是静态方法,所以通过类名.直接调用 -
sort(List list) : 对于list集合进行一个默认的升序排列(从小到大排列)
-
binarySearch(List list, Object key) : 检索key在list集合中的索引位置,返回值类型int类型,如果找到了,返回一个>=0的int整数;如果没有找到返回一个负数
注意 : 1. 要求list集合升序排列 2. 通过结果是否>=0 来进行判断元素key是否存在于集合中 -
max(Collection c) : 将集合中的最大值获取到,一般比较数值比较有意义
-
min(Collection c) : 将集合中的最小值获取到,一般比较数值比较有意义
-
shuffle(List list) : 将list集合中的数据任意打乱
使用场景 : 类似扑克牌中洗牌,需要每次将牌任意打乱
代码
package com.zgjy.doudizhu;
import java.util.ArrayList;
import java.util.Collections;
public class CollectionsDemo {
// Collections工具类的常用方法
public static void main(String[] args) {
// 1. sort(List list) : 对于list集合进行一个默认的升序排列(从小到大排列)
ArrayList arr = new ArrayList<>();
arr.add(12);
arr.add(-8);
arr.add(1);
arr.add(99);
arr.add(0);
Collections.sort(arr);
System.out.println(arr);// [-8, 0, 1, 12, 99]
// 2.binarySearch(List list, Object key) :
//检索key在list集合中的索引位置,返回值类型int类型,如果找到了,返回一个>=0的int整数;如果没有找到返回一个负数
// 注意 : 1. 要求list集合升序排列 2. 通过结果是否>=0 来进行判断元素key是否存在于集合中
int index = Collections.binarySearch(arr, 99);
System.out.println(index);// 4
//[-8, 0, 1,11, 12, 99]
int index1 = Collections.binarySearch(arr, 11);
System.out.println(index1);// -4
// 3.max(Collection c) : 将集合中的最大值获取到,一般比较数值比较有意义
// 4.min(Collection c) : 将集合中的最小值获取到,一般比较数值比较有意义
int max = Collections.max(arr);
int min = Collections.min(arr);
// 99-----8
System.out.println(max + "----" + min);
//5.shuffle(List list) : 将list集合中的数据任意打乱
Collections.shuffle(arr);
System.out.println(")))"+arr);
}
}
- 斗地主案例
按照斗地主的规则,完成洗牌发牌的动作。
具体规则:
1. 组装54张扑克牌
2. 将54张牌顺序打乱
3. 三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张留作底牌。
4. 查看三人各自手中的牌(按照牌的大小排序)、底牌
手中扑克牌从大到小的摆放顺序:大王,小王,2,A,K,Q,J,10,9,8,7,6,5,4,3
分析:
代码
package com.zgjy.doudizhu;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class DouDiZhu {
/*
* 1. 组合54张牌
* 2. 洗牌
* 3. 三个玩家+底牌的发牌
* 4. 看牌
*
* */
public static void main(String[] args) {
// 1. 设置牌的4个花色
String[] flower = {“♥”,“♠”,“♦”,“♣”};
// 2. 准备牌
String[] puke = {“2”,“A”,“K”,“Q”,“J”,“10”,“9”,“8”,“7”,“6”
,“5”,“4”,“3”};
// 3.创建一个Map集合,用于装54张牌和牌号码的对应关系
Map<Integer, String> map = new HashMap<Integer, String>();
// 创建一个List集合,用于存放所有牌的牌号,为了后面洗牌和发牌
ArrayList list = new ArrayList<>();
// 定义一个牌号的初始值,0和1留给大王和小王
int count = 2;
for(String pai : puke) {// 2
for(String f : flower) {
// 4. 将准备好的带有花色的牌放置到map集合中,还有对应的牌号
map.put(count, f+pai);
list.add(count);
count++;
}
}
map.put(0, "大王");
list.add(0);
map.put(1, "小王");
list.add(1);
// 5. 洗牌,将list中的所有牌号打乱
Collections.shuffle(list);
// 6. 创建三个玩家牌的容器,以及底牌容器
ArrayList<Integer> play1 = new ArrayList<>();
ArrayList<Integer> play2 = new ArrayList<>();
ArrayList<Integer> play3 = new ArrayList<>();
ArrayList<Integer> bottom = new ArrayList<>();
// 7. 发牌,三个玩家,没人17张,底牌3张
// 实际上发给玩家的是list集合中的牌号,循环发牌
// 前3张发给底牌
for(int i = 0 ; i < list.size() ; i ++ ) {
if( i < 3 ) {// 发给底牌
bottom.add(list.get(i));
}else {// 剩下所有牌发给3个玩家
if( i % 3 == 0) {// 发给玩家1
play1.add(list.get(i));
}else if( i % 3 == 1) {// 发给玩家2
play2.add(list.get(i));
}else if( i % 3 == 2) {// 发给玩家3
play3.add(list.get(i));
}
}
}
// 8. 看牌
lookPai(play1,map,"玩家1");
lookPai(play2,map,"玩家2");
lookPai(play3,map,"玩家3");
lookPai(bottom,map,"底牌");
}
// 看牌的方法封装
public static void lookPai(ArrayList play,Map<Integer, String> map , String name) {
// 1.先将玩家手中的牌号进行升序排列,对应的牌从大到小
Collections.sort(play);
//2. 通过牌号到map集合中获取到真实的value值,就是真实牌
System.out.print(name + ": ");
for(Integer key : play) {
String value = map.get(key);
System.out.print(value + " ");
}
System.out.println();
}
}