JavaSE基础——(18)Map集合

目录

一、Map集合

1.1Map集合概述

1.2Map集合与Collection集合的区别

1.3Map功能概述

二、Map集合的遍历

2.1根据键集合迭代 

2.2根据键值对对象迭代

2.3增强for循环遍历

三、键为自定义对象

四、LinkedHashMap集合

五、TreeMap集合

六、统计字符串中每个字符出现次数

七、HashMap与Hashtable的区别

八、模拟斗地主洗牌和发牌练习

九、泛型固定上下边界(待补充)

9.1泛型固定上边界

9.2泛型固定下边界


一、Map集合

1.1Map集合概述

java中Map用于保存具有映射关系的数据,Map集合里保存着两组值,

一组用于保存Map的key,另一组保存着Map的value,Map是一个将键值映射到值的接口,

一个映射不能包含重复的键值,每个键最多映射到一个值。

1.2Map集合与Collection集合的区别

  • Map存储的是两组值,而Collection是一组值
  • Map的键是唯一的,Collection的子接口Set键是唯一的
  • Map集合的数据结构值针对键有效,和值无关;而Collection集合的数据结构是针对元素有效的

1.3Map功能概述

  • 添加功能
    • V put(K key,V value)//添加元素
      • 如果键为第一次存储,则直接存储元素,返回null
      • 如果键已经存在了,那么就用值将以前的旧值替换掉,返回以前的值
  • 删除功能
    • void clear()//删除所有的键值对元素
    • V remove(Object key)//根据键删除键值对元素,并将值返回
  • 判断功能
    • boolean containsKey(Object key)//判断集合是否包含指定的键
    • boolean containsValue(Object value)//判断集合是否包含指定的值
    • boolean isEmpty()//判断集合是否为空
  • 获取功能
    • Set<Map.Entry<K,V>> entrySet()
    • V get(Object key)//根据键获取值
    • Set<K> ketSet()//获取集合中所有键的集合
    • Collection<V> values()//获取集合中所有值的集合
  • 长度功能
    • int size()//返回集合中键值对的个数

二、Map集合的遍历

2.1根据键集合迭代 

由于Map中没有迭代器的方法,所以我们对Map集合进行遍历的时候,

首先会获取键的集合keySet,然后通过keySet的迭代器遍历所有的键,

最后通过键获取对应的值,达到对Map集合的遍历效果,下面是程序演示,

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class MapTest {
    public static void main(String[] args) {
        Map<String,Integer> map=new HashMap<>();
        map.put("测试1",21);
        map.put("测试2",22);
        map.put("测试3",23);

        Set<String> ketSet=map.keySet();
        Iterator<String> it=ketSet.iterator();
        while(it.hasNext()){
            String key=it.next();
            Integer i=map.get(key);
            System.out.println(key+"="+i);
        }
    }
}

2.2根据键值对对象迭代

我们将双列集合的键值对,变为单列集合的键值对对象,

然后遍历这个集合,获取每个键值对对象,根据键值对对象,从而获取键和值的大小,

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class MapTest {
    public static void main(String[] args) {
        Map<String,Integer> map=new HashMap<>();
        map.put("测试1",21);
        map.put("测试2",22);
        map.put("测试3",23);

        //Map.Entry说明Entry是Map的内部接口,将键和值封装成了Entry对象并存储在Set集合中
        Set<Map.Entry<String,Integer>> entrySet=map.entrySet();
        Iterator<Map.Entry<String,Integer>> it=entrySet.iterator();
        while(it.hasNext()){
            Map.Entry<String,Integer> entry=it.next();
            System.out.println(entry.getKey()+"="+entry.getValue());
        }
    }
}

2.3增强for循环遍历

我们还可以使用增强for循环对Map集合进行遍历,这种方式会更简单一些,

import java.util.HashMap;
import java.util.Map;

public class MapTest {
    public static void main(String[] args) {
        Map<String,Integer> map=new HashMap<>();
        map.put("测试1",21);
        map.put("测试2",22);
        map.put("测试3",23);

        for(String key:map.keySet()){
            System.out.println(key+"="+map.get(key));
        }
    }
}

三、键为自定义对象

如果我们用自定义的对象当作键存储到HashMap中,集合如果还要保证键的唯一性,

则必须重写自定义对象中的equals方法和hashCode方法,

我们测试一下,键为Student自定义对象,值为籍贯字符串,

import java.util.HashMap;

public class MapTest {
    public static void main(String[] args) {
        HashMap<Student,String> hashMap=new HashMap<>();
        hashMap.put(new Student("测试1",21),"武汉");
        hashMap.put(new Student("测试1",21),"长沙");
        hashMap.put(new Student("测试1",21),"郑州");
        hashMap.put(new Student("测试1",21),"南昌");

        System.out.println(hashMap);
    }
}

可以看到,前面的Student对象属性相同的只存进来了最后一个值,键相同就会不断覆盖掉前面的值。

四、LinkedHashMap集合

LinkedHashMap就是使用链表实现的HashMap,其特点是存取顺序一致,我们简单测试一下:

    public static void main(String[] args) {
        LinkedHashMap<String,Integer> linkedHashMap=new LinkedHashMap<>();
        linkedHashMap.put("测试1",21);
        linkedHashMap.put("测试3",23);
        linkedHashMap.put("测试2",22);

        System.out.println(linkedHashMap);
    }

五、TreeMap集合

TreeMap与TreeSet类似,也是一个有序的集合,存储的为键值对,为两列集合,

同理,如果这个键为自定义对象,则要在自定义对象中继承Comparable,并实现compareTo方法,

    public static void main(String[] args) {
        TreeMap<Student,String> treeMap=new TreeMap<>();
        treeMap.put(new Student("测试1",23),"武汉");
        treeMap.put(new Student("测试2",22),"长沙");
        treeMap.put(new Student("测试3",21),"郑州");

        System.out.println(treeMap);
    }

同时我们也可以在TreeMap构造的时候传一个比较器的方法来指定排序的规则,

我们更改一下排序规则,按照姓名来排序,测试一下看看效果,

    public static void main(String[] args) {
        TreeMap<Student,String> treeMap=new TreeMap<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                int num=o1.getName().compareTo(o2.getName());
                return num==0?o1.getAge()-o2.getAge():num;
            }
        });
        treeMap.put(new Student("测试1",23),"武汉");
        treeMap.put(new Student("测试2",22),"长沙");
        treeMap.put(new Student("测试3",21),"郑州");

        System.out.println(treeMap);
    }

六、统计字符串中每个字符出现次数

要求给定一个字符串,需要统计里面每个字符出现的次数,

public class MapTest {
    public static void main(String[] args) {
        String str="aaabbbbbccd";
        char arr[]=str.toCharArray();

        HashMap<Character,Integer> hashMap=new HashMap<>();
        for(char c:arr){
            if(!hashMap.containsKey(c)){
                hashMap.put(c,1);
            }else{
                hashMap.put(c,hashMap.get(c)+1);
            }
        }

        System.out.println(hashMap);
    }
}

七、HashMap与Hashtable的区别

HashMap和Hashtable底层都是哈希算法支持的,都为双列集合,存储的是键与值,

但是它们主要有以下几点区别,

  • Hashtable是线程安全的,效率低,Hashtable不可以存储null键和null值
  • HashMap是线程不安全的,效率高,HashMap可以存储null键和null值

八、模拟斗地主洗牌和发牌练习

import java.util.ArrayList;
import java.util.Collections;

public class MapTest {
    public static void main(String[] args) {
        String num[]={"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
        String color[]={"方片","梅花","黑桃","红桃"};
        ArrayList<String> poker=new ArrayList<>();

        //添加扑克牌到牌库
        for(String pokerColor:color){
            for(String pokerNum:num){
                poker.add(pokerColor.concat(pokerNum));//concat链接俩字符串
            }
        }
        poker.add("小王");
        poker.add("大王");

        //洗牌
        Collections.shuffle(poker);//随机打乱原来的顺序

        //发牌
        ArrayList<String> player1=new ArrayList<>();
        ArrayList<String> player2=new ArrayList<>();
        ArrayList<String> player3=new ArrayList<>();
        ArrayList<String> cardsOfLandlord=new ArrayList<>();

        for (int i = 0; i <poker.size() ; i++) {
            if(i>=poker.size()-3){
                cardsOfLandlord.add(poker.get(i));
            }else if(i%3==0){
                player1.add(poker.get(i));
            }else if(i%3==1){
                player2.add(poker.get(i));
            }else if(i%3==2){
                player3.add(poker.get(i));
            }
        }

        //看牌
        System.out.println("玩家一手牌:"+player1);
        System.out.println("玩家二手牌:"+player2);
        System.out.println("玩家三手牌:"+player3);
        System.out.println("地主奖励底牌:"+cardsOfLandlord);
    }
}

我们可以发现这个时候手牌是没有顺序的,现在我们利用HashMap构建键值对,

将54个扑克牌对应好54个数字(注意这里的54个数字对应的大小关系就是我们想要扑克牌排序的大小关系,比如梅花3对应0,梅花4就对应4,梅花5对应8以此类推),

然后在ArrayList里面直接存储着54个数字,随机打乱,

然后使用TreeSet存储这54个数字,存储的时候按照我们想要的排序关系来存储,

最后显示出来就可以看到手牌是有序的,下面我们试一下效果,

import java.util.*;

public class MapTest {
    public static void main(String[] args) {
        String num[]={"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
        String color[]={"♦","♣","♠","♥"};
        HashMap<Integer,String> pokerHash=new HashMap<>();
        ArrayList<Integer> pokerList=new ArrayList<>();

        //构造好扑克牌的HashMap
        for(int i=0;i<num.length;i++){
            for(int j=0;j<color.length;j++){
                pokerHash.put(i*4+j,color[j].concat(num[i]));//concat链接俩字符串
            }
        }
        pokerHash.put(52,"小王");
        pokerHash.put(53,"大王");

        //添加对应数字到数组中
        for (int i = 0; i < 54; i++) {
            pokerList.add(i);
        }

        //洗牌
        Collections.shuffle(pokerList);//随机打乱原来的顺序

        //发牌
        TreeSet<Integer> player1=new TreeSet<>();
        TreeSet<Integer> player2=new TreeSet<>();
        TreeSet<Integer> player3=new TreeSet<>();
        TreeSet<Integer> cardsOfLandlord=new TreeSet<>();

        for (int i = 0; i <pokerList.size() ; i++) {
            if(i>=pokerList.size()-3){
                cardsOfLandlord.add(pokerList.get(i));
            }else if(i%3==0){
                player1.add(pokerList.get(i));
            }else if(i%3==1){
                player2.add(pokerList.get(i));
            }else if(i%3==2){
                player3.add(pokerList.get(i));
            }
        }

        //看牌
        System.out.print("玩家1手牌:");
        Iterator<Integer> it1=player1.iterator();
        while(it1.hasNext()){
            Integer it=it1.next();
            System.out.print(pokerHash.get(it)+" ");
        }
        System.out.println();

        System.out.print("玩家2手牌:");
        Iterator<Integer> it2=player2.iterator();
        while(it2.hasNext()){
            Integer it=it2.next();
            System.out.print(pokerHash.get(it)+" ");
        }
        System.out.println();

        System.out.print("玩家3手牌:");
        Iterator<Integer> it3=player3.iterator();
        while(it3.hasNext()){
            Integer it=it3.next();
            System.out.print(pokerHash.get(it)+" ");
        }
        System.out.println();

        System.out.print("地主奖励底牌:");
        Iterator<Integer> it4=cardsOfLandlord.iterator();
        while(it4.hasNext()){
            Integer it=it4.next();
            System.out.print(pokerHash.get(it)+" ");
        }
    }
}

九、泛型固定上下边界(待补充)

9.1泛型固定上边界

? extends E

通俗理解就是只要是E的子类或者同类对象,就可以将父类对象指向子类引用。

9.2泛型固定下边界

? super E

通俗理解就是E中是实现的一些功能,E的子类也可以使用。

猜你喜欢

转载自blog.csdn.net/weixin_39478524/article/details/112779447
今日推荐