Map集合的遍历;HashMap;HashTable;LinkedHashMap;Map和Collection的区别;Collections工具类(Java Day16)

一,Map集合的遍历

  • 概述:map集合不能够单独遍历,只能间接的进行遍历。
  • ​ 采用的思路:先把双列集合转换为单列集合,通过单例集合的遍历得到其中的一部分数据通过map集合的或者是其他的相关方法得到另一部分数组,从而达到遍历双列集合的效果
  • 如何变成单列集合?
  1. ​ 方式一:纵向切割法

​           1.1  双列集合纵向的看就只有 key 和 value 这样的两列,从 key 和 value 中间切开,变成了两列,每列的数据都存放到一个容器中,map集合里面得到 key可以找到对应的value,所有优先操作key这一列的数据,得到key 再通过map集合的get(K k)得到对应的value

​       2.   方式二:横向切割法

​           2.1  map集合有几对数据就有几行,把一对一对的数据切割开来变成单独的数据,把每一个单独的数据封装到一个entry对象的属性key和value【此处的key和value不是map的key和value是 entry 对象的属性名称】这样就可以得到多个entry对象,然后把这些entry对象同意放在一个容器【Set集合】

  • 遍历方式有两种:
  1. 键找值方式

​          步骤:

​               1.1、通过 map 对象调用 keySet 得到 map 集合所有 key 的 set 集合

​               1.2、遍历 set 集合

​               1.3、在遍历 set集合 的循环体中使用 map集合对象 调用get(key)得到对​应的value

​ 原理图:

​ 

​     2.  键值对对象方式 ​

         步骤:

             ​2.1、把map集合变成 entry对象 的set集合【map集合有一个方法 entrySet,就可以干这件事】

​             2.2、遍历 entry 对象的集合

​             2.3、在遍历的过程中通过 getter方法 获取对应的 key和 value

​ 原理图:

​ 

代码示例


import java.util.Collection;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;
public class Demo_Map {
 public static void main(String[] args) {
    HashMap<String, String> map = new HashMap<>();
    map.put("宝宝", "蓉蓉");
    map.put("乃亮", "小璐");
    map.put("伊利", "文章");
    map.put("金莲", "大朗");
//第一种遍历方法:键找值 //双列集合变单列集合,set为无序的单列集合 Set<String> set = map.keySet(); System.out.println(set); //[乃亮, 金莲, 伊利, 宝宝] //遍历set集合 //foreach: 数据类型 变量名:要遍历的容器{拿到元素处理逻辑} for (String key : set) { String value = map.get(key); //得到key对应的value System.out.println(key+"**"+value); } System.out.println("-----------------------"); //第二种遍历方法:键值对方式遍历 //entrySet()将map集合中每个元素封装成Entry对象后保存到Set集合 Set<Entry<String, String>> set2 = map.entrySet(); //为什么entry对象的属性的数据类型可以自动的和map集合的key和value的数据类型一样 //因为entry是map的内容接口 entry是map的一部分,所以entry的泛型和map集合的泛型使用的同一个泛型 //遍历entry的set集合得到每一个entry对象 System.out.println(set2); //[乃亮=小璐, 金莲=大朗, 伊利=文章, 宝宝=蓉蓉] for (Entry<String, String> entry : set2) {
         //.getKey() 和 .getValue()  获取键和值
//获取key属性的值也就是map的key 的值
        String key = entry.getKey();
        //获取value 属性的值 也就是map的value的值
        String value = entry.getValue();
        System.out.println(key+"**"+value);
    }
    //如果只是单纯的得到 map集合的value值,可以用Collection的values方法
    Collection<String> values = map.values();
    System.out.println(values);    //[小璐, 大朗, 文章, 蓉蓉]
}
}
  • 补充:
  1. 纵向切割的时候分别可以得到 key 和 value 的集合,
  2. ​ key的集合:通过keySet()得到
  3. ​ value的集合:通过values()方法得到 Collection集合【如果以后只想单纯的得到map集合的value值】

二,HashMap

  • 概述:它是Map集合的典型的实现类,没有自己的特有特点和功能,无非就是为了事项Map接口的所有一切。
  • 功能:
  1. put:  增加和修改元素
  2. remove:  根据键删除值
  3. clear :  清空所有集合元素
  4. get(key):   根据键获取值
  5. containsKey:  判断map集合的key中是否包含参数
  6. containsValue:  判断map集合的value中是否包含参数
  7. ​ keySet:  获取map集合所有key的set集合
  8. entrySet:  获取所有键值对数据对应的键值对对象的set集合
  9. values:  获取map集合所有value的单列集合
  10.  size(): 获取集合的长度
  • 遍历方式和 map 是一样的。[[ 键找值、键值对 ]]
  • 如何保证Hashmap的key存放对象的内容是唯一性

  • ​ map集合的键有唯一不可重复的特点;不可重复体现在两点:
  1. ​ 第一点:对象不一样【地址值不一样就是不一样】比较简单,不需要做任何的事情,只需要把对象当做键存入到 map集合 即可
  2. ​ 第二点:对象的值不一样【对象的属性值不一样,不包括地址值不一样属性值一样】
  • ​ 需要既要对地址值进行保证也要对内容值进行保证,要同时达到这样的效果,需要在对象对应的类中重写 hashCode equals 方法
  • 唯一性和 hashSet 原理是一样的:
  1. 是因为HashSet底层是使用HashMap来存放数据并实现
  2. 都是根据hash值来存放数据的

代码示例

//定义Student类
public class Student { private String name; private int age; public Student(String name, int age) { super(); this.name = name; this.age = age; } @Override public String toString() { return "Student [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; Student other = (Student) 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; } } //定义测试类 import java.util.HashMap; public class Student_Test { public static void main(String[] args) { HashMap<Student, String> map = new HashMap<>(); map.put(new Student("柏芝", 42),"九龙"); // key 就是Student的内容,student里面已重写方法 map.put(new Student("柏芝", 42),"尖沙咀"); //尖沙咀属于修改后的内容 map.put(new Student("张敏",55),"浅水湾"); map.put(new Student("林青霞",60),"铜锣湾"); map.put(null,"铜锣湾"); //添加成功,key值是可以为null map.put(new Student("林青霞",60),null); //添加成功 value也可以为null map.put(null, null); //修改成功了,修改了(null,铜锣湾) System.out.println(map);//重写了hashcode和equals方法所以相同的就只添加一次,出来的是修改后的内容,唯一性 } }
  • HashMap的key可不可以为null,value的值可不可以为null?

  • ​ 可以的而且支持同时为mull ​ null为键的时候不管是否重写hashCode和equals方法都是唯一的一个key

三,HashTable

  • 概述:是Map集合早期的典型实现类,没有字独有的功能和特点,完全是为了实现map的功能而出现的,在jdk1.2版本之后逐步被 HashMap 取代使用位置。
  • 底层是由哈希表组成,所以无序,不支持null 键,但线程安全。
  • 他的使用方式和 HashMap 使用是一模一样,无非就是调用的时候换个对象
  • HashMap和 HashTable:【面试题】

  • 相同点:都是Map集合的典型实现类。功能的使用是一模一样的
  • 不同点:
  1. 出现的时间不同【HashTable 早于 HashMap】
  2. HashTable 是线程安全的,HashMap 是线程不安全的
  3. HashTable 是效率是低的,HashMap 是效率高的
  4. ​ HashTable 的 key 和 value 不支持null值;HashMap 支持 null值的

代码示例

import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
public class Student_Test {
    public static void main(String[] args) {
        HashMap<Student,String> map = new HashMap<>();
        map.put(new Student("柏芝",23), "九龙");
        map.put(new Student("柏芝",23), "尖沙咀");
        map.put(new Student("张敏",40), "新界");
        map.put(new Student("朱茵",50), "铜锣湾");
        map.put(null, "铜锣湾");//添加成功了,key可以为null
        map.put(new Student("朱茵",50), null);//添加成功了  value也可以为null
        map.put(null, null);//修改成功了   null最为键的时候不管是否重写hashCode和equals方法都是唯一的一个key 
        System.out.println(map);
        System.out.println("==============");
        Hashtable<Student, String> hashtable = new Hashtable<>();
        hashtable.put(new Student("柏芝",23), "九龙");
        hashtable.put(new Student("柏芝",23), "尖沙咀");
        hashtable.put(new Student("张敏",40), "新界");
        hashtable.put(new Student("朱茵",50), "铜锣湾");
        //hashtable.put(null, "铜锣湾");//添加成功了,key可以为null
        //hashtable.put(new Student("朱茵",50), null);//添加成功了  value也可以为null
        //hashtable.put(null, null);
        System.out.println(hashtable);
    }
}

四,LinkedHashMap

  • 概述:他是 HashMap的子类,同样也是Map的实现类。他的功能全部来自Map的共有功能。Map集合是无序的。但是这个实现类是有序的。但是其他的特征和Map的特征的一致。
  • 遍历方式和 Map 的遍历方式也是一样的。[[ 键找值;键值对对象 ]]

代码示例

import java.util.HashMap;
import java.util.LinkedHashMap;
public class Demo_LinkedHashMap {
    public static void main(String[] args) {
        HashMap<Student, String> map = new HashMap<>();
        map.put(new Student("柏芝", 42),"九龙");  // key 就是Student的内容,student里面已重写方法
        map.put(new Student("柏芝", 42),"尖沙咀"); //尖沙咀属于修改后的内容
        map.put(new Student("张敏",55),"浅水湾"); 
        map.put(new Student("林青霞",60),"铜锣湾"); 
        map.put(null,"铜锣湾");  //添加成功,key值是可以为null
        map.put(new Student("林青霞",60),null); //添加成功 value也可以为null
        map.put(null, null); //修改成功了,修改了(null,铜锣湾)
        System.out.println(map);//重写了hashcode和equals方法所以相同的就只添加一次,出来的是修改后的内容,唯一性
        System.out.println("--------------------------");
        
        LinkedHashMap<Student, String>map2 = new LinkedHashMap<>();
        map2.put(new Student("柏芝", 42),"九龙"); 
        map2.put(new Student("柏芝", 42),"尖沙咀"); 
        map2.put(new Student("张敏",55),"浅水湾");
        map2.put(new Student("林青霞",60),"铜锣湾"); 
        System.out.println(map2);  //输出有序
    }
}

五,Map和Collection的区别

  • 相同点:都是存放引用数据类型数据的容器
  • 不同点:
  1. ​ 位置上存放的元素个数不一样:Map是一对【键值对数据Collection 放的是一个
  2. Map里面有序的只有LinkedHashMapCollection有 List 体系和 LinkedHashSet
  3. Map不能直接遍历Collection可以直接遍历,遍历方式一共四种

六,Collections工具类

  • 概述:用来处理Collection集合中数据的一些相关功能的工具类 类似 Arrays
  • 常用方法:
  1. int binarySearch(List list, E e):  二分查找法查找e元素在list集合的第一次出现的索引。使用前提list 需要升序排好了。
  2. fill(List list, E e):  使用e填充满集合list【使用元素e替换list集合原有的元素】。使用前提list 集合中必须要有元素
  3. int frequency(Collection c,E e):  返回集合c中的e元素的个数【计数】
  4. max:  返回集合中的最大值
  5. min:  返回集合中的最小值
  6. replaceAll(List list,E olde ,E newe):  使用news将集合中的olde元素全部替换
  7. reverse(List list):  反转list集合中的元素位置
  8. shuffer(List list):  将list集合中的元素全部打乱
  9. swap(List list,int a ,int b ):  将list集合中a索引的值和b索引的值进行互换
  10. sort(List list):  将list的元素进行了升序排序

代码示例:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
public class Demo_Collections {
public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<>();
    list.add(23);
    list.add(12);
    list.add(43);
    list.add(43);
    list.add(57);
    list.add(57);
    list.add(2);
    list.add(2);
    
    ArrayList<String> list1 = new ArrayList<>();
    list1.add("23");
    list1.add("12");
    list1.add("43");
    list1.add("57");
    list1.add("57");//没有排序找到的不一定是第一次出现的那个角标值
    list1.add("2");

    int i = Collections.binarySearch(list1,"57");  
    System.out.println(list1); //[23, 12, 43, 57, 57, 2]
    System.out.println(i);  //57的角标值是4
    
    Collections.sort(list1);// 默认是升序
    System.out.println(list1);//字符串排序是按首字母来排序的[12, 2, 23, 43, 57, 57]
    int j = Collections.binarySearch(list1,"57");  
    System.out.println(j); //4
    
    Collections.sort(list);
    System.out.println(list); //[2, 2, 12, 23, 43, 43, 57, 57]
    int k = Collections.binarySearch(list,57);
    System.out.println(k);//6
    
    ArrayList<Object> list2 = new ArrayList<>();
    list2.add(100);
    list2.add(100);
    list2.add(200);
    list2.add(300);
    Collections.fill(list2,30);//用30替换集合里面的元素, 集合里面必须要有元素
    System.out.println(list2);
    
    int num = Collections.frequency(list2, 30);
    System.out.println(num); //4,30的元素有4个,没有的话就是0
    
    Integer max = Collections.max(list);
    Integer min = Collections.min(list);
    System.out.println(max+"=="+min);//57==2,集合里面的最大值与最小值
    
    Collections.replaceAll(list2, 30, "你好");
    System.out.println(list2);//[你好, 你好, 你好, 你好],把30全部替换成了字符“你好”,因为list2是object类型所以可以转换为字符
    //fill方法是把集合里面的所有的元素替换,replaceAll方法只替换指定的元素其它的元素不替换
    
    System.out.println(list); //[2, 2, 12, 23, 43, 43, 57, 57]
    Collections.reverse(list);
    System.out.println(list); //[57, 57, 43, 43, 23, 12, 2, 2] 反转
    
    Collections.swap(list, 3, 5);
    System.out.println(list); //[57, 57, 43, 12, 23, 43, 2, 2] 3角标与5角标互换
    
    Collections.shuffle(list);
    System.out.println(list);  //将集合里面的全部元素打乱
    
}
}
  • 综合案例:斗地主
  • 使用双列集合完成斗地主案例【发牌到看牌的过程】
  • 分析:
  1. 准备牌:

                 1.1  存放牌的容器【双列集合】

                 1.2  生成并存放牌【组合牌】

                 ​1.3  牌由花色和数字组成的以及大小王

                 ​1.4  准备花色和数字

                 1.5 ​ 花色和 数字去拼接就成为了牌

                 1.6 ​ 把牌存到map集合【存放到哪里合适?】

                 1.7 ​ 牌存在map的value上,key可以是牌的编号

​       2.  洗牌

​                2.1  使用shuffer方法洗牌,洗的List 集合 是一个双列集合

​                2.2  洗编号所在的list集合

      3.  发牌

​                3.1  怎么发牌合适,牌能直接发吗?

​                3.2  每三张一轮回 可不可以给牌设置编号

​            【使用编号所在的list集合的索引对3取余根据值不同发给不同的人但是最后的三张不需要取余,直接留给底牌】发牌的时候发编号 ,

      4.  看牌

​                4.1  看牌的时候只要把编号换成对应的牌就可以了

代码示例

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Set;
public class Poker {
public static void main(String[] args) {
//第一步:准备牌
//准备牌,存放牌的容器 [双列集合] //牌是string类型的,编号是integer类型的 HashMap<Integer, String> poker_map = new HashMap<>(); //定义一个poker的初始的编号 int id = 1; //准备花色和数字 String[] color_arr = "♠️,♥️,♣️,♦️".split(","); //用split切开 String[] num_color = "2,3,4,5,6,7,8,9,10,A,J,Q,K".split(","); //组合数组加花色 for (String num : num_color) { for (String color : color_arr) { //花色和数字拼接成了牌,得到一张牌 String poker = color+num; //把牌存放到map集合的value上,key是牌的编号 //将得到的牌放到容器里面 poker_map.put(id++, poker); //id为编号 } } poker_map.put(id++, "大王"); poker_map.put(id++, "小王"); System.out.println(poker_map);//加上大小王得到完整的有顺序的一副牌
//第二步:洗牌
//使用shuffer方法洗牌 Set<Integer> keySet = poker_map.keySet();// 双列集合变为单列集合,需要将编号打乱 System.out.println(keySet);//得到有顺序的编号 //需要把set集合转变为list集合,这个集合是放编号的 ArrayList<Integer> list = new ArrayList<>(); list.addAll(keySet); //将set集合放到list集合里面 Collections.shuffle(list);//需要一个list 集合 System.out.println(list);// 打乱编号
//第三步:发牌
//发的是底牌都是牌的编号所以是integer类型,接收的容器,底牌需要容器,玩家也需要容器 list容器 ArrayList<Integer> dipai_list_id = new ArrayList<>(); ArrayList<Integer> baobao_list_id = new ArrayList<>(); ArrayList<Integer> nailiang_list_id = new ArrayList<>(); ArrayList<Integer> yufan_list_id = new ArrayList<>(); //通过索引来发牌,发的是list编号 for (int i = 0; i < list.size(); i++) { //先把最后的三张牌留作底牌,需要容器所以在发牌之前需要有接收的容器 if(i >= 51) { //如果角标大于等于51,52/53/54留作底牌 dipai_list_id.add(list.get(i)); //留三张底牌 }else if(i % 3 == 0) { //对3取余,第一张牌的索引为0,i 为索引值,打乱顺序后根据索引整除3的逻辑进行取牌,因为是3个人所以用3进行整除 baobao_list_id.add(list.get(i)); // 发给第一个人,第一个人的牌 }else if (i % 3 == 1) { //除3取余等于1 nailiang_list_id.add(list.get(i));//等于1的时候发给第二个人 }else if(i % 3 == 2) {//除3取余等于2 yufan_list_id.add(list.get(i)); //如果前面的都不满足的话就发给第三个人,这里遍历完里面都是索引值 } }

//第四步:看牌
//看牌的时候只要把编号换成对应的牌就可以了 System.out.print("羽凡的牌:"); // yufan_list_id里面是索引的集合 for (Integer integer : yufan_list_id) { //遍历羽凡的牌,遍历一个编号得到一个对应的牌,对应的每一个索引都有相应的牌,总共54个索引值 System.out.print(poker_map.get(integer)+" "); //拿到的牌,打印的时候不能换行,get(integer),就相当于get(key)值 } System.out.println(); System.out.print("乃亮的牌:"); for (Integer integer : nailiang_list_id) { System.out.print(poker_map.get(integer)+" "); } System.out.println(); System.out.print("宝宝的牌:"); for (Integer integer : baobao_list_id) { System.out.print(poker_map.get(integer)+" "); } System.out.println(); System.out.print("底牌:"); for (Integer integer : dipai_list_id) { System.out.print(poker_map.get(integer)+" "); } } }
原文地址:https://www.cnblogs.com/nastu/p/12489140.html