目录
一、Map的含义
二、Map的特点
三、Map结构图
四、Map常用方法
五、HashMap
(1)使用HashMap演示以上方法
(2)Map遍历
(3)案例
六、HashTable
七、TreeMap
八、LinkedHashMap
九、斗地主练习
一、Map的含义
Map:双列集合的顶层接口
Map:单词含义,地图,地图上的每个点,都表示了生活中的一个具体位置。地图的点和生活中的位置,有一个一一对应的关系,这种关系是通过穷举的方式来描述的。
Map是一个以键(key)值(value)对形式存储数据的容器。
二、Map的特点
Map 是一个接口,但不是Collection的子接口。
Map以键值对的形式存储数据,每个键(key)对应一个值(value)。
Map 中的键不能重复(唯一)。
Map 中的值可以重复。
主要实现类 HashMap Hashtable TreeMap ...
三、Map结构图
四、Map常用方法
put(K key, V value) 向Map中添加数据
putAll(Map<? extends K,? extends V> m) 向Map中添加另一个Map集合。
isEmpty() Map中是否包含数据
size() Map中包含键值对的个数
get(key) 根据key获取value
clear() 清空Map
containsKey(key) 判断Map中是否包含key
containsValue(value) 判断Map中是否包含value
keySet() 返回Map中所有key 组成的Set集合
values() 返回Map中所有value组成的集合 (返回值Collection类型)
entrySet() 返回此映射中包含的映射关系的 Set 视图
五、HashMap
HashMap是Map接口的最常用实现类,底层是哈希表形式存储的,非线程安全的,允许有null键值对。
(1)使用HashMap演示以上方法
public static void main(String[] args) {
Map<String,String> map = new HashMap<String,String>();
map.put("aaa","111"); // key不能重复,value 可以重复
map.put("bbb","222");
map.put("ccc", "333");
map.put("ddd", "111"); // value可以重复
map.put(null,null);
System.out.println(map.put("aaa", "100")); // key不能重复,会覆盖原有的value
// put方法的返回值 是存入这个key时,之前这个key值在map中对应的value值
System.out.println(map.size()); // 获得Map中包含多少元素
String str = map.get("aaa"); // 根据key获取value
System.out.println(str);
String str2 = map.get("xxx"); // 当key不存在时返回null
System.out.println(str2);
System.out.println(map.containsKey("aaa")); // 判断是否包含某个key
System.out.println(map.containsKey("xxx"));
System.out.println(map.containsValue("222")); //判断是否包含某个value
System.out.println(map.containsValue("555"));
map.remove("aaa"); // 根据key删除数据
System.out.println(map.get("aaa"));
System.out.println(map.isEmpty()); //判断map中是否包含数据
map.clear(); // 清空map
System.out.println(map.isEmpty());
}
(2)Map遍历
方式一:使用keySet()方法
1、获取Map集合中的所有键,放到一个Set集合中,遍历该Set集合,获取到每一个键,根据键再来获取对应的值。【根据键获取值】
2、获取Map集合中的所有键
Set<K> keySet()
Set<String> keys = map.keySet();
for(String key:keys){
System.out.println(key+"--->"+map.get(key));
}
方式二:使用entrySet()方法
获取Map集合中的所有键值对对象(Entry),到Set集合中,遍历Set集合,拿到的是每个键值对对象(Entry),从这个对象中分别获取键和值。【根据键值对对象获取键和值】
根据Map集合获取所有的键值对对象,到一个Set集合中
Set<Map.Entry<K, V>> entrySet()
Entry是Map接口中的内部接口,访问的方式:Map.Entry
Entry的常用方法:
getKey()获取当前键值对对象的键
getValue()获取当前键值对对象的值
Set<Map.Entry<String,String>> es = map.entrySet();
for(Map.Entry<String,String> entry:es){
//System.out.println(entry);
System.out.println(entry.getKey()+"--->"+entry.getValue());
}
(3)案例
案例1:编写一个方法,完成英译汉翻译功能。
dog--->狗
cat--->猫
pig--->猪
monkey--->猴
cow---> 牛
public class Demo03_Map练习_英译汉 {
public static void main(String[] args) {
String result = translate("lion");
if(result!=null){
System.out.println(result);
}else{
System.out.println("查无此词");
}
}
public static String translate(String word){
// 词典
Map<String,String> map = new HashMap<String, String>();
map.put("cat", "猫");
map.put("dog", "狗");
map.put("monkey", "猴子");
map.put("pig", "猪");
map.put("elephant", "大象");
map.put("tiger", "老虎");
map.put("fox", "狐狸");
map.put("lion", "狮子");
String result = map.get(word);
return result;
}
}
案例2:键盘录入一个字符串,统计每个字符出现的次数
例如,录入aaaabbccddd!@#@#$@#$%cc66ff
打印出来:a有4个,b有2个,c有4个,d有3个,!有1个,@有3个,$有2个,%有1个,6有2个,f有2个
public class Demo04_Map练习_统计字符出现的次数 {
/*
键盘录入一个字符串,统计每个字符出现的次数
例如,录入aaaabbccddd!@#@#$@#$%cc66ff
打印出来:a有4个,b有2个,c有4个,d有3个,!有1个,@有3个,$有2个,%有1个,6有2个,f有2个
思路:
1 使用Map key-->字符 value-->次数
2 遍历字符串取到字符
3 判断取到的字符在map的key中是否存在 存在,根据key取出次数 再+1 存回去。 不存在,把取到字符当成key存入map并存入次数(value) 1
* */
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
Map<String,Integer> map = new HashMap<String, Integer>();
for(int i=0;i<str.length();i++){
char c = str.charAt(i);
String key = c+"";
//Integer count = map.get(c+""); // 为null 说明map中没有这个字符
boolean flag = map.containsKey(key);
int count = 0;
if(flag){
count = map.get(key);
}
map.put(key, ++count);
}
Set<Map.Entry<String,Integer>> set = map.entrySet();
for(Map.Entry<String,Integer> entry:set){
System.out.println(entry.getKey()+" : "+entry.getValue());
}
}
}
六、HashTable
Hashtable是一个比较古老的类(从JDK1.2开始),特点是线程安全的,不允许有null键值对。用法和HashMap相同,基本被HashMap替代。
1、面试常见问题HashMap和Hashtable的区别?
HashMap: 线程不安全,允许null键值对
Hashtable: 线程安全,不允许null键值对
七、TreeMap
特点:会根据key值进行升序排列。
public class Demo06_TreeMap {
/*
* 底层是由红黑数(自平衡的二叉树)来实现的 会根据key升序排序
* key需要有排序的能力 或传入比较器
* */
public static void main(String[] args) {
Map<String,String> map = new TreeMap<String,String>();
map.put("bbb","222");
map.put("ddd","444");
map.put("eee","555");
map.put("ccc","333");
map.put("aaa","111");
Set<Map.Entry<String,String>> set = map.entrySet();
for(Map.Entry<String,String> entry:set){
System.out.println(entry.getKey()+"---"+entry.getValue());
}
}
}
八、LinkedHashMap
是HashMap的一个子类
和HashMap的不同之处在于,具有可预知的迭代顺序,存储键值对的顺序和遍历集合时取出键值对的顺序一致。
public class Demo07_LinkedHashMap {
public static void main(String[] args) {
/*
LinkedHashMap 是 HashMap的子类 不同在于 LinkedHashMap有序(和添加顺序一致)
*/
Map<String,String> map = new LinkedHashMap<String,String>();
map.put("aaa","111");
map.put("bbb","222");
map.put("ccc","333");
map.put("ddd","444");
Set<Map.Entry<String,String>> set = map.entrySet();
for(Map.Entry<String,String> entry:set){
System.out.println(entry.getKey()+" "+entry.getValue());
}
}
}
九、斗地主练习
斗地主的制牌、洗牌和发牌
思路
1、制牌:1~K一共13个数字,四个花色,4 * 13张牌,小王、大王
2、洗牌:shuffle将集合中的字符串随机置换
3、发牌:将一个集合中的元素,分发到3个集合中
问题
发牌之后,每个人的牌都没有顺序,无法洗牌,字符串的字典顺序,和扑克牌中的大小顺序不同,不能使用字典顺序来直接排序
解决
1、通过穷举,手动将所有牌面的大小,全都定义出来,每个牌面上的字符串,都可以对应一个其在扑克牌中的大小的数字(字符串和数字的对应关系)
2、可以给牌面的大小排序,对应到某个牌面
发牌后不带自动排序的实现
public class Demo02_斗地主_制牌_洗牌_发牌 {
public static void main(String[] args) {
String[] nums = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
String[] colors = {"红桃","黑桃","梅花","方块"};
List<String> poker = new ArrayList()<String>();
//制牌
for(String color:colors){
for(String num:nums){
poker.add(color+num);
}
}
poker.add("小王");
poker.add("大王");
//洗牌
Collections.shuffle(poker);
//发牌
List<String> xiaodao = new ArrayList<String>();
List<String> longwu = new ArrayList<String>();
List<String> me = new ArrayList<String>();
List<String> dipai = new ArrayList<String>();
for(int i=1;i<=3;i++){
dipai.add(poker.remove(0));
}
while(true){
if(!poker.isEmpty()){
xiaodao.add(poker.remove(0));
}
if(!poker.isEmpty()){
longwu.add(poker.remove(0));
}
if(!poker.isEmpty()){
me.add(poker.remove(0));
}else{
break;
}
}
System.out.println(dipai);
System.out.println(xiaodao);
System.out.println(longwu);
System.out.println(me);
}
}
发牌后带自动排序的实现
public class Demo03_斗地主_制牌_洗牌_发牌_有序 {
public static void main(String[] args) {
String[] nums = { "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2" };
String[] colors = { "红桃", "黑桃", "梅花", "方块" };
// 要制作一个表格,表格中存放的是 序号和牌的对应
Map<Integer, String> table = new HashMap<Integer, String>();
// Poker中只存序号就可以了,以后要用牌的时候,就到table中根据序号取到对应的牌即可
List<Integer> poker = new ArrayList<Integer>();
int count = 0;
for (String num : nums) {
for (String color : colors) {
table.put(count, color + num); // 把序号和生成的牌装入table表格中
poker.add(count);
count++;
}
}
table.put(count, "小王");
poker.add(count);
count++;
table.put(count, "大王");
poker.add(count);
// 洗牌
Collections.shuffle(poker);
// 发牌
List<Integer> dipai = new ArrayList<Integer>();
List<Integer> xiaodao = new ArrayList<Integer>();
List<Integer> longwu = new ArrayList<Integer>();
List<Integer> me = new ArrayList<Integer>();
for (int i = 1; i <= 3; i++) {
dipai.add(poker.remove(0));
}
while (true) {
if (!poker.isEmpty()) {
xiaodao.add(poker.remove(0));
}
if (!poker.isEmpty()) {
longwu.add(poker.remove(0));
}
if (!poker.isEmpty()) {
me.add(poker.remove(0));
}else{
break;
}
}
Collections.sort(xiaodao);
Collections.sort(longwu);
Collections.sort(me);
System.out.println(kanpai(dipai,table));
System.out.println(kanpai(xiaodao,table));
System.out.println(kanpai(longwu,table));
System.out.println(kanpai(me,table));
}
public static String kanpai(List<Integer> list,Map<Integer,String> map){
StringBuilder sb = new StringBuilder("[");
for(Integer x:list){
sb.append(map.get(x)).append(",");
}
return sb.replace(sb.length()-1,sb.length(),"]").toString();
}
}