【小白看的Java教程】第三十六章,牛头对马嘴:Map【荐】

认识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。

image.png

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

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

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

注意:

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

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

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 entrySet():返回Map中所有键值对所组成的Set集合

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

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); 

    }

}

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=貂蝉}

集合框架工具类和方法

Arrays(掌握)

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

+ public static List 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对象的长度是固定的,不能增,也不能减。

Collections(了解)

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

斗地主发牌案例(了解)

按照斗地主游戏的规则,模拟对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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值