美文网首页
Java中的Map入门

Java中的Map入门

作者: 王一萍o叩丁狼教育 | 来源:发表于2018-09-13 21:28 被阅读0次

1.1. Map接口(重点)

1.1.1. 认识Map(理解)

Map,翻译为映射,在数学中的解释为:

设A、B是两个非空集合,如果存在一个法则f,使得A中的每个元素a,按法则f,在B中有唯一确定的元素b与之对应,则称f为从A到B的映射,记作f:A→B。

image.png

也就是说映射表示两个集合之间各自元素的一种“对应”的关系,在面向对象中我们使用Map来封装和表示这种关系。

image.png

从定义和结构图上,可以看出Map并不是集合,而表示两个集合之间的一种关系,故Map没有实现Collection接口。

在Map中,要求A集合中的每一个元素都可以在B集合中找到唯一的一个值与之对应。这句话可以解读为一个A集合元素只能对应一个B集合元素,也就说A集合中的元素是不允许重复的,B集合中的元素可以重复,也可不重复。那么不难推断出A集合应该是一个Set集合,B集合应该是List集合。 [图片上传失败...(image-2b76fc-1536844564929)]

我们把A集合中的元素称之为key,把B集合中的元素称之为value。

image.png

其实能看出一个Map其实就有多个key-value(键值对)组成的,每一个键值对我们使用Entry表示。

image.png

不难发现,一个Map结构也可以理解为是Entry的集合,即Set<Entry>。

image.png

一般的,我们依然习惯把Map称之为集合,不过要区分下,Set和List是单元素集合,Map是双元素集合。

  • 单元素集合:每次只能存储一个元素,比如Set和List。

  • 双元素集合:每次需要存储两个元素(一个key和一个value),比如Map。

注意:

  • Map接口并没有继承于Collection接口也没有继承于Iterable接口,所以不能直接对Map使用for-each操作。

  • 如果不能理解Map的结构,就直接记住Map每次需要存储两个值,一个是key,一个是value,其中value表示存储的数据,而key就是这一个value的名字。

1.1.2. Map常用的API方法(记住)

添加操作

  • boolean put(Object key,Object value):存储一个键值对到Map中

  • boolean putAll(Map m):把m中的所有键值对添加到当前Map中

删除操作

  • Object remove(Object key):从Map中删除指定key的键值对,并返回被删除key对应的value

修改操作

  • 无专门的方法,可以调用put方法,存储相同key,不同value的键值对,可以覆盖原来的。

查询操作

  • int size():返回当前Map中键值对个数

  • boolean isEmpty():判断当前Map中键值对个数是否为0.

  • Object get(Object key):返回Map中指定key对应的value值,如果不存在该key,返回null

  • boolean containsKey(Object key):判断Map中是否包含指定key

  • boolean containsValue(Object value):判断Map中是否包含指定value

  • Set keySet():返回Map中所有key所组成的Set集合

  • Collection values():返回Map中所有value所组成的Collection集合

  • Set<Entry> entrySet():返回Map中所有键值对所组成的Set集合

注意,标红的是重度使用的方法。

1.1.3. HashMap(重点)

HashMap底层基于哈希表算法,Map中存储的key对象的hashCode值决定了在哈希表中的存储位置,因为Map中的key是Set,所以不能保证添加的先后顺序,也不允许重复。

需求1:操作Map接口常用方法

public class HashMapDemo1{

    public static void main(String[] args) {

        Map<String, String> map = new HashMap<>();

        map.put("girl1", "西施");

        map.put("girl2", "王昭君");

        map.put("girl3", "貂蝉");

        map.put("girl4", "杨玉环");

        System.out.println("map中有多少键值对:"+map.size());

        System.out.println(map);

        System.out.println("是否包含key为girl1:"+map.containsKey("girl1"));

        System.out.println("是否包含value为貂蝉:"+map.containsValue("貂蝉"));

        //替换key为girl3的value值

        map.put("girl3", "小乔");

        System.out.println(map);

        //删除key为girl3的键值对

        map.remove("girl3");

        System.out.println(map);

    }

}

Map的迭代遍历:

//获取Map中所有的key

Set<String> keys = map.keySet();

System.out.println("Map中所有key:"+keys);

//获取Map中所有的value

Collection<String> values = map.values();

System.out.println("Map中所有value:"+values);

//获取Map中所有的key-value(键值对)

Set<Entry<String, String>> entrys = map.entrySet();

for (Entry<String, String> entry : entrys) {

    String key = entry.getKey();

    String value = entry.getValue();

    System.out.println(key+"->"+value);

}

需求2:统计一个字符串中每隔字符出现次数

public class HashMapDemo2{

    public static void main(String[] args) {

        String str = "ABCDEFABCDEABCDABCABA";

        //把字符串转换为char数组

        char[] charArray = str.toCharArray();

        //Map的key存储字符,value存储出现的次数

        Map<Character, Integer> map = new HashMap<>();

        //迭代每一个字符

        for (char ch : charArray) {

            //判断Map中是否已经存储该字符

            if (map.containsKey(ch)) {

                Integer count = map.get(ch);

                //如果已经存储该字符,则把出现次数加上1

                map.put(ch, count+1);

            }else {

                //如果没有存储该字符,则把设置次数为1

                map.put(ch, 1);

            }

        }

        System.out.println(map); 

    }

}

1.1.4. TreeMap(了解)

TreeMap底层基于红黑树算法,因为Map中的key是Set,所以不能保证添加的先后顺序,也不允许重复,但是Map中存储的key会默认使用自然排序(从小到大),和TreeSet一样,除了可以使用自然排序也可以自定义排序。

需求:测试HashMap和TreeMap中key的顺序

public class App {

    public static void main(String[] args) {

        Map<String, String> map = new HashMap<>();

        map.put("girl4", "杨玉环");

        map.put("girl2", "王昭君");

        map.put("key1", "西施");

        map.put("key3", "貂蝉");

        System.out.println(map);

        //-------------------------------------------

        map = new TreeMap<>(map);

        System.out.println(map);

    }

}

输出结果:

{key1=西施, girl4=杨玉环, key3=貂蝉, girl2=王昭君}

{girl2=王昭君, girl4=杨玉环, key1=西施, key3=貂蝉}

2. 集合框架工具类和方法

2.1. Arrays(掌握)

Arrays类是数据的工具类,其中有一个方法比较常用。

  • public static <T> List<T> asList(T... a):该方法可以把一个Object数组转换为List集合。
public class ArraysDemo{

    public static void main(String[] args) {

        //把Integer[]转换为List<Integer>

        List<Integer> list1 = Arrays.asList(1, 2, 3);

        System.out.println(list1);

        //把String[]转换为List<String>

        List<String> list2 = Arrays.asList("A", "B", "C");

        System.out.println(list2);

    }

}

注意通过Arrays.asList方法得到的List对象的长度是固定的,不能增,也不能减。

2.2. Collections(了解)

Collections是集合的工具类,封装了Set、List、Map操作的工具方法,比如拷贝、排序、搜索、比较大小等。

2.3. 斗地主发牌案例(了解)

按照斗地主游戏的规则,模拟对54张扑克牌的洗牌和发牌以及对手中牌排序操作。

具体规则:

  • 将54张不同花色的扑克牌打乱(♠♣♥♦☻)

  • 三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张留作底牌

  • 查看三人各自手中的牌(按照牌的大小排序)、底牌

  • 手中扑克牌从大到小的摆放顺序:大王、小王、2、A、K、Q、J、10、9、8、7、6、5、4、3

首先我们定义好基本的代码测试框架:

 public class App { 
    public static void main(String[] args) {

    }

}

接下来,使用一个列表来记录四中花色:

        //花色♠♣♥♦
        List<String> colors = new ArrayList<>();
        colors.add("♠");
        colors.add("♣");
        colors.add("♥");
        colors.add("♦");

然后,想办法添加牌面。牌面有2~A;一共四种花色,所以我们可以使用一个列表,来添加4份2-A的牌面:

        //数字345678910JQKA2
        List<String> numbers = new ArrayList<>();
        Collections.addAll(numbers, 
"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2");
        numbers.addAll(numbers);//把13张复制成26张
        numbers.addAll(numbers);//把26张复制成52张

牌面最终要和花色对应,为了后面的发牌操作方便,我们定义一个Map<Integer,String>,key是我们定义的排序,可以简单的理解为我们为每一张牌定义了一个编号,value就是具体的排面+花色,相当于每一张牌和一个具体的序号一一对应:

        //大小王: 大☻ 小☻
        //定义Map,用数字来记录每一张牌
        Map<Integer, String> map = new HashMap<>();
        Integer squence = 0;//牌的顺序
        //加入其它牌
        for (String number : numbers) {
            for (String color : colors) {
                //一副牌54张,序号范围在[0,51]之间
                if (squence <= 51) {
                    map.put(squence, number + "(" + color + ")");
                    squence++;
                }
            }
        }
        map.put(squence, "小☻");
        squence++;
        map.put(squence, "大☻");
        squence++;

洗牌:

        //使用0~53来记录每一张牌
        List<Integer> cards = new ArrayList<>(map.keySet());
        Collections.shuffle(cards);
        System.out.println(cards);

接下来定义三个玩家的牌列表,然后为最后剩下的底牌定义一个列表在存放:

        //三个玩家和底牌
        List<Integer> player1 = new ArrayList<Integer>();
        List<Integer> player2 = new ArrayList<Integer>();
        List<Integer> player3 = new ArrayList<Integer>();
        List<Integer> end = new ArrayList<Integer>();

发牌:

        //发牌
        for (int index = 0; index < cards.size(); index++) {
            if (index < 51) {
                int mod = index % 3;//index除以3的余数
                int card = cards.get(index);
                if (mod == 1) {
                    player1.add(card);
                } else if (mod == 2) {
                    player2.add(card);
                } else {
                    player3.add(card);
                }
            } else {
                end.add(cards.get(index));
            }
        }

每个玩家手牌排序:

        System.out.println(player1);
        System.out.println(player2);
        System.out.println(player3);
        System.out.println(end);
        //排序
        Collections.sort(player1);
        Collections.sort(player2);
        Collections.sort(player3);
        Collections.sort(end);

注意,到这里为止,每个玩家手上的牌,仍然不是具体的牌,只是每张牌对应的序号,接下来我们就要通过序号找到对应的牌:

        //各自手上的牌
        List<String> player1Cards = new ArrayList<>();
        List<String> player2Cards = new ArrayList<>();
        List<String> player3Cards = new ArrayList<>();
        List<String> endCards = new ArrayList<>();

        for (Integer key : player1) {
            player1Cards.add(map.get(key));
        }
        for (Integer key : player2) {
            player2Cards.add(map.get(key));
        }
        for (Integer key : player3) {
            player3Cards.add(map.get(key));
        }
        for (Integer key : end) {
            endCards.add(map.get(key));
        }

看牌:

        //看牌
        System.out.println("玩家1:" + player1Cards);
        System.out.println("玩家2:" + player2Cards);
        System.out.println("玩家3:" + player3Cards);
        System.out.println("底牌  :" + endCards);

到此,发牌操作结束。

集合框架小结

List、Set、Map选用
一般的在存储元素时候,是否需要给元素起一个名字:

  • 需要:此时使用Map。
  • 不需:存储的元素使用需要保证先后添加的顺序
  • 需要:此时使用List
  • 不需:此时使用Set(如果需要保证集合元素不重复,也选用Set)

若要获得最好的学习效果,需要配合对应教学视频一起学习。需要完整教学视频,请参看https://ke.qq.com/course/272077

相关文章

网友评论

      本文标题:Java中的Map入门

      本文链接:https://www.haomeiwen.com/subject/cubggftx.html