第十四章 集合(Set、Collections、Map、集合嵌套)
文章目录
前言
一、Set系列集合
1、Set系列集系概述
Set系列集合特点
- 无序:存储顺序不一致
- 不重复:可以去除重复
- 无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素。
Set集合实现类特点
- HashSet:无序、不重复、无索引。
- LinkedHashSet:有序、不重复、无索引。
- TreeSet:排序、不重复、无索引。
Set集合的功能上基本上与Collection的API一致。
2、HashSet元素无序的底层原理:哈希表
HashSet底层原理
- HashSet集合底层采取哈希表存储的数据。
- 哈希表是一种对于增删改查数据性能都较好的结构。
哈希表的组成
- JDK8之前的,底层使用数组+链表组成
- JDK8开始后,底层采用数组+链表+红黑树组成。
在了解哈希表之前需要先理解哈希值的概念
哈希值
- 是JDK根据对象的地址,按照某种规则算出来的int类型的数值。
Object类的API
- public int hashCode(): 返回对象的哈希值
对象的哈希值特点
- 同一个对象多次调用hashCode()方法返回的哈希值是相同的
- 默认情况下,不同对象的哈希值是不同的。
3、HashSet元素去重复的底层原理
4、实现类:LinkedHashSet
5、实现类:TreeSet
TreeSet集合概述和特点
- 不重复、无索引、可排序
- 可排序:按照元素大小默认升序(由小到大)排序
- TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好
- 注意:TreeSet集合是一定要排序的,可以将元素按照指定的规则进行排序
二、Collection体系的特点、使用场景总结
三、补充知识:可变参数
四、补充知识:集合工具类Collections
五、Collection体系的综合案例
Card.java
public class Card {
private String size;
private String color;
private int index; //真正的大小
public Card() {
}
public Card(String size, String color, int index) {
this.size = size;
this.color = color;
this.index = index;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
@Override
public String toString() {
return size +color;
}
}
GameDemo.java
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
目标:斗地主游戏的案例开发。
业务需求分析:
斗地主的做牌, 洗牌, 发牌, 排序(拓展知识), 看牌。
业务: 总共有54张牌。
点数: "3","4","5","6","7","8","9","10","J","Q","K","A","2"
花色: "♠", "♥", "♣", "♦"
大小王: "👲" , "🃏"
点数分别要组合4种花色,大小王各一张。
斗地主:发出51张牌,剩下3张作为底牌。
功能:
1.做牌。
2.洗牌。
3.定义3个玩家
4.发牌。
5.排序(拓展,了解,作业)
6.看牌
*/
public class GameDemo {
/**
1、定义一个静态存储的集合存储54张牌对象
*/
public static List<Card> allCards = new ArrayList<>();
/**
2、做牌:定义静态代码块初始化牌数据
*/
static {
//3、定义点数:个数确定,类型确定,使用数组
String[] sizes = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
//4、定义花色:个数确定,类型确定,使用数组
String[] colors = {"♠", "♥", "♣", "♦"};
//5、组合点数和花色
int index = 0; //记录牌的大小
for (String size : sizes) {
index++;
for (String color : colors) {
//6、封装成一个牌对象
Card c = new Card(size, color, index);
//7、存入到集合容器中去
allCards.add(c);
}
}
//8、大小王存入到集合对象中去"👲" , "🃏"
Card c1 = new Card("","🃏", ++index);
Card c2 = new Card("","👲", ++index);
Collections.addAll(allCards, c1, c2);
System.out.println("新牌:" + allCards);
}
public static void main(String[] args) {
//9、洗牌
Collections.shuffle(allCards);
System.out.println("洗牌后:" + allCards);
//10、发牌(定义三个玩家,每个玩家的牌也是一个集合容器)
List<Card> linghuchong = new ArrayList<>();
List<Card> jiumozhi = new ArrayList<>();
List<Card> renyingying = new ArrayList<>();
//11、开始发牌(从牌集合中发出51张牌给三个玩家,剩余三张作为底牌)
//allCards = [5♣, J♥, K♥, 3♦, 10♥, 10♦, 10♣ ...
// i 1 2 3 4 5 6 7 % 3
for (int i = 0; i < allCards.size() - 3; i++) {
//先拿到当前牌对象
Card c = allCards.get(i);
if(i % 3 ==0){
//请阿冲接牌
linghuchong.add(c);
}else if (i % 3 ==1){
//请阿鸠接牌
jiumozhi.add(c);
}else if (i % 3 == 2){
//请盈盈接牌
renyingying.add(c);
}
}
//12、拿到最后三张底牌(把最后三张牌截取成一个子集合)
List<Card> lastThreeCards = allCards.subList(allCards.size() - 3 , allCards.size());
//13、给玩家的牌排序(从大到小 可以先自己试试)
sortCards(linghuchong);
sortCards(jiumozhi);
sortCards(renyingying);
//14、输出玩家的牌
System.out.println("阿冲:" + linghuchong);
System.out.println("阿鸠:" + jiumozhi);
System.out.println("盈盈:" + renyingying);
System.out.println("最后三张底牌:" + lastThreeCards);
}
/**
给牌排序
* @param cards
*/
private static void sortCards(List<Card> cards){
Collections.sort(cards, new Comparator<Card>() {
@Override
public int compare(Card o1, Card o2) {
return o2.getIndex() - o1.getIndex();
}
});
}
}
六、Map集合体系
1、Map集合的概述
2、Map集合体系特点
3、Map集合常用API
4、Map集合的遍历方式一:键找值
5、Map集合的遍历方式二:键值对
6、Map集合的遍历方式三:lambda表达式
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
需求:统计投票人数
*/
public class MapTest1 {
public static void main(String[] args) {
//1、把80个学生选择的数据拿进来
String[] selects = {"A", "B", "C", "D"};
StringBuilder sb = new StringBuilder();
Random r = new Random();
for (int i = 0; i < 80; i++) {
sb.append(selects[r.nextInt(selects.length)]);
}
System.out.println(sb);
//2、定义一个Map集合记录最终统计的结果:A=30 B=20 C=20 D=10
Map<Character, Integer> infos = new HashMap<>();
//3、遍历80个学生选择的数据
for (int i = 0; i < sb.length(); i++) {
//4、提取当前选择景点字符
char ch = sb.charAt(i);
//5、判断Map集合中是否存在这个键
if (infos.containsKey(ch)){
//让其值+1
infos.put(ch, infos.get(ch) + 1);
}else {
//说明此景点是第一次被选
infos.put(ch, 1);
}
}
//4、输出集合
System.out.println(infos);
}
}
7、Map集合的实现类HashMap
8、Map集合的实现类LinkedHashMap
9、Map集合的实现类TreeMap
七、补充知识:集合的嵌套
import java.util.*;
/**
需求:统计投票人数
*/
public class MapTest4 {
public static void main(String[] args) {
//1、要求程序记录每个学生选择的情况
//使用一个Map集合存储
Map<String, List<String>> data = new HashMap<>();
//2、把学生选择的数据存入进去
List<String> selects = new ArrayList<>();
Collections.addAll(selects, "A", "C");
data.put("罗勇", selects);
List<String> selects1 = new ArrayList<>();
Collections.addAll(selects1, "B", "C", "D");
data.put("胡桃", selects1);
List<String> selects2 = new ArrayList<>();
Collections.addAll(selects2, "A", "B", "C", "D");
data.put("刘军", selects2);
System.out.println(data);
//3、统计每个景点选择的人数
Map<String, Integer> infos = new HashMap<>();
//4、提取所有人选择的景点信息
Collection<List<String>> values = data.values();
System.out.println(values);
//values = [[B, C, D], [A, B, C, D], [A, C]]
// value
for (List<String> value : values) {
for (String s : value) {
//有没有包含这个景点
if (infos.containsKey(s)){
infos.put(s,infos.get(s) + 1);
}else {
infos.put(s, 1);
}
}
}
System.out.println(infos);
}
}