Map集合
1.1 概述
现实生活中,我们常会看到这样的一种集合:IP地址与主机名,身份证号与个人,系统用户名与系统用户对象等,这种一一对应的关系,就叫做映射。Java提供了专门的集合类用来存放这种对象关系的对象,即java.util.Map
接口。
-
Collection接口,定义了单列集合规范,每次存储一个元素,单个元素,孤立存在
-
Map接口,定义了双列集合的规范,每次存储一对儿元素,成对存在:
Map<key,value>,key和value的数据类型,可以相同也可以不同
将键映射到值的对象,一个映射不能包含重复的键;每个键最多只能映射到一个值。
键唯一,但是值可以重复,一个键对应一个值,通过键可以找到值
1.2 Map常用子类
-
HashMap<K,V>:存储数据采用的**哈希表**结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
底层:哈希表 无须集合,存取顺序不一致
-
LinkedHashMap<K,V>:HashMap下有个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构。通过链表结构可以保证元素的存取顺序一致;通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
底层:哈希表+链表 有序集合,存取顺序一致
1.3 Map接口中常用方法
-
public V put(K key, V value)
: 把指定的键与指定的值添加到Map集合中。/* 返回值:V 在进行存储的时候,如果key值不存在,则会存入,并且返回null 如果key重复,就会用新的Value去替换原来的Value,然后返回被替换的value值 */ package Demo06; import java.util.HashMap; import java.util.Map; public class DemoMap { public static void main(String[] args) { show01(); } private static void show01() { Map<String,String> map = new HashMap<>(); String v = map.put("吃饭","喝茶"); System.out.println(v); //null String v2 = map.put("吃饭","喝饮料"); System.out.println(v2); //喝茶 } }
-
public V remove(Object key)
: 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。map.put("告辞","拜拜"); map.put("吃饭","喝饮料"); map.put("喝水","吃饭"); map.put("百事","可口"); map.put("椰奶","椰汁"); System.out.println(map); //{吃饭=喝饮料, 百事=可口, 椰奶=椰汁, 喝水=吃饭, 告辞=拜拜} String v = map.remove("吃饭"); System.out.println(v); //喝饮料
-
public V get(Object key)
根据指定的键,在Map集合中获取对应的值。String v1 = map.get("百事"); System.out.println(v1); //可口
-
boolean containsKey(Object key)
判断集合中是否包含指定的键。boolean boo = map.containsKey("告辞"); System.out.println(boo); //true
-
public Set<K> keySet()
: 获取Map集合中所有的键,存储到Set集合中。 -
public Set<Map.Entry<K,V>> entrySet()
: 获取到Map集合中所有的键值对对象的集合(Set集合)。
1.4 Map集合遍历方式
- 获取Map中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键。方法提示:
keyset()
- 遍历键的Set集合,得到每一个键。
- 根据键,获取键所对应的值。方法提示:
get(K key)
-
public Set<K> keySet()
: 获取Map集合中所有的键,存储到Set集合中。package Demo06; import java.util.*; public class DemoMap { public static void main(String[] args) { Map<String, String> map = new HashMap<>(); map.put("告辞", "拜拜"); map.put("吃饭", "喝饮料"); map.put("喝水", "吃饭"); map.put("百事", "可口"); map.put("椰奶", "椰汁"); Set<String> set = map.keySet(); System.out.println(set); //[吃饭, 百事, 椰奶, 喝水, 告辞] //迭代器 Iterator<String> it = set.iterator(); while (it.hasNext()) { String key = it.next(); System.out.println(key+':'+ map.get(key)); } //增强for for (String i: set) { System.out.println(i+':'+map.get(i)); } } } /* 吃饭:喝饮料 百事:可口 椰奶:椰汁 喝水:吃饭 告辞:拜拜 */
-
public Set<Map.Entry<K,V>> entrySet()
: 获取到Map集合中所有的键值对对象的集合(Set集合)。package Demo06; import java.util.*; public class DemoMap { public static void main(String[] args) { Map<String, String> map = new HashMap<>(); map.put("告辞", "拜拜"); map.put("吃饭", "喝饮料"); map.put("喝水", "吃饭"); map.put("百事", "可口"); map.put("椰奶", "椰汁"); Set<Map.Entry<String,String>> setmap = map.entrySet(); System.out.println(setmap); //[吃饭=喝饮料, 百事=可口, 椰奶=椰汁, 喝水=吃饭, 告辞=拜拜] Iterator<Map.Entry<String,String>> it = setmap.iterator(); while(it.hasNext()){ Map.Entry<String,String> entry = it.next(); System.out.println(entry.getKey()+ ':'+entry.getValue()); } for (Map.Entry<String,String> i: setmap) { System.out.println(i.getKey()+ ':'+i.getValue()); } } } /* 吃饭:喝饮料 百事:可口 椰奶:椰汁 喝水:吃饭 告辞:拜拜 */
1.5 Map集合存储自定义集合
作为键的值如果为自定义类型,比如所Person类,那么就需要重写hashCode方法和equals方法,来保证不唯一
//Perosn
package Demo06;
import java.util.Objects;
public class Person{
private int age;
private String name;
......
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(age, name);
}
}
package Demo06;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class DemoPerson {
public static void main(String[] args) {
HashMap<Person,String> map = new HashMap<>();
map.put(new Person(18,"Rain"),"北京");
map.put(new Person(23,"Jerry"),"上海");
map.put(new Person(36,"Tom"),"郑州");
map.put(new Person(24,"Nacy"),"长沙");
map.put(new Person(18,"Rain"),"武汉");
//当重写了两个方法后,相同的Person就不会出现
Iterator<Map.Entry<Person, String>> iterator = map.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry<Person,String> entry = iterator.next();
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
}
1.6 LinkedHashMap集合
LinkedHashMap继承了HashMap集合
底层为哈希表+链表(记录顺序)
package Demo06;
import java.util.HashMap;
import java.util.LinkedHashMap;
public class DemoLinkedHashMap {
public static void main(String[] args) {
HashMap<String,String> map = new HashMap<>();
map.put("a","a");
map.put("c","c");
map.put("b","b");
map.put("a","d");
System.out.println(map); //{a=d, b=b, c=c}
//不允许重复,但是存入输出数据顺序不同
LinkedHashMap<String,String> link = new LinkedHashMap<>();
link.put("a","a");
link.put("c","c");
link.put("b","b");
link.put("a","d");
System.out.println(link); //{a=d, c=c, b=b}
不允许重复,但是存入输出数据顺序相同
}
}
1.7 HashTable
跟HashMap一样,底层是哈希表
和HashMap不同的是,任何的非null对象都能作为键或则值
HashMap和HashTable的区别:
- table是一个线程安全的集合,是单线程的,速度比较慢
- map是一个线程不安全的集合,是多线程的,速度比较快
- 之前学的所有的集合都是可以存储null值的,不论是键还是值
- table不能存储空值
package Demo06;
import java.util.HashMap;
import java.util.Hashtable;
public class DemoHashTable {
public static void main(String[] args) {
HashMap<String,String> map = new HashMap<>();
map.put(null,"a");
map.put("b",null);
map.put(null,null);
System.out.println(map); //允许出现空,空也算一个键,{null=null, b=null}
Hashtable<String,String> table = new Hashtable<>();
table.put(null,"a");
table.put("b",null);
table.put(null,null);
System.out.println(table); //会报出空指针异常,Exception in thread "main" java.lang.NullPointerException
}
}
1.8 Debug追踪
Debug调试程序:
可以让代码逐行执行,查看代码执行的过程,调试程序中出现的bug
使用方式:
- 用My Eclipse,在行号右边点击,出现大红圆点,来添加断点(哪里有bug添加在哪里)
- 添加断点后,右键使用Debug执行程序,程序就会停留在第一个断点处
- F8:逐行执行语句;F7:进入到方法中;Shift+F8:跳出方法;F9:跳到下一个断点(如果没有下一个断点,就停止程序);Ctrl+F2:退出Debug模式,停止程序;
斗地主案例升级版(到手的牌有序)
分析:
-
准备牌
54张牌,其中包括两张特殊的牌:大小王
其他52张牌:
-
定义以一个数组/集合,包括四种花色:桃、心、梅、方
-
定义以一个数组/集合,面值:A、2、3、…、K
将两个集合组合起来变成剩余的52张
利用map集合键值对的形式,key为0-53的数字,value对应不同的牌
然后创建一个普通的集合list,用来存放0-53的数字
-
-
洗牌:使用集合工具类Collections的方法
static void shuffle(List<?> List)
使用指定的随机源对指定的列表进行置换会
随机打乱
集合中的元素;注意,这个时候打乱集合list的顺序,也就是将集合中0-53打乱 -
摸牌:要求1人17张牌,剩余三张作为底牌,一人一张轮流发牌:
集合的索引(0-53)%3
定义4个集合,分别存储3个玩家的牌和底牌
索引%3,有三个值(0,1,2)
索引>=51,给底牌发牌
这个时候发给每个人的值是0-53当中的数字
-
排序:使用Collections中的
soft(list)
方法 -
看牌:通过每个人手中的数字,作为map集合的键,对应到map集合的value,然后将value值取出打印
package DouDiZhu;
import java.util.*;
public class DemoDDZ_2 {
public static void main(String[] args) {
//定义两个数组分别存花色和数值
String[] color = {"♠","♥","♣","♦"};
String[] number = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
//将大小王先放到扑克集合中
Map<Integer,String> map = new LinkedHashMap<>();
map.put(52,"SmallJoker");
map.put(53,"BigJoker");
//循环嵌套两个数组,组装52张牌,并把牌放到扑克集合当中
//一个键对应一个值,例如52,对应小王,53对应大王
int i = 0;
while(i <= 51){
for (String numbers : number) {
for (String colors : color) {
map.put(i,colors+numbers);
i++;
}
}
}
//定义一个poker ArrayList集合,里面存放的是map集合当中的键
ArrayList<Integer> poker = new ArrayList<>();
for (int j = 0; j <= 53; j++) {
poker.add(j);
}
//打乱顺序
Collections.shuffle(poker);
//定义四个集合来,代表三个人和底牌集合
ArrayList<Integer> people1 = new ArrayList<>();
ArrayList<Integer> people2 = new ArrayList<>();
ArrayList<Integer> people3 = new ArrayList<>();
ArrayList<Integer> lastPoker = new ArrayList<>();
//发牌
int k = 0;
while (k <= 50){
if (k%3 == 0){
people1.add(poker.get(k));
}else if (k%3 == 1){
people2.add(poker.get(k));
}else if (k%3 == 2){
people3.add(poker.get(k));
}
k++;
}
//把最后的三张牌作为底牌,放到底牌集合中
lastPoker.add(poker.get(51));
lastPoker.add(poker.get(52));
lastPoker.add(poker.get(53));
//对每个人手中的牌进行排序,注意:这个时候每个人手中的其实是0-53中的数值,每个数字代表一张牌,现在是对数字进行排序
Collections.sort(people1);
Collections.sort(people2);
Collections.sort(people3);
Collections.sort(lastPoker);
//看牌,通过获取每个人手中的数字,拿到map集合中,获取每个数字对应的是什么牌
System.out.println("三千七百万:"+ print(map,people1));
System.out.println("反手一个超级加倍:"+ print(map,people2));
System.out.println("闷声发大财慈善家:"+ print(map,people3));
System.out.println("底牌:"+ print(map,lastPoker));
}
public static ArrayList<String> print(Map<Integer,String> map,ArrayList<Integer> list){
ArrayList<String> strList = new ArrayList<>();
for (Integer i:list) {
String value = map.get(i);
strList.add(value);
}
return strList;
}
}
/*
三千七百万:[♥3, ♠4, ♣4, ♣6, ♠7, ♥8, ♣8, ♥9, ♠10, ♦J, ♠Q, ♠A, ♥A, ♣A, ♠2, ♦2, SmallJoker]
反手一个超级加倍:[♦3, ♦4, ♠5, ♥5, ♣5, ♠6, ♦6, ♥7, ♦7, ♠8, ♣9, ♦10, ♥J, ♦Q, ♣K, ♣2, BigJoker]
闷声发大财慈善家:[♠3, ♣3, ♥4, ♦5, ♥6, ♦8, ♠9, ♦9, ♠J, ♣J, ♥Q, ♣Q, ♠K, ♥K, ♦K, ♦A, ♥2]
底牌:[♣7, ♥10, ♣10]
*/