写在前面:

每一个不曾起舞的日子,都是对生命的辜负。

希望看到这里的每一个人都能努力学习,不负韶华,成就更好的自己。


以下仅是个人学习过程中的一些想法与感悟,Java知识博大精深,作为初学者,个人能力有限,哪里写的不够清楚、明白,还请各位不吝指正,欢迎交流与讨论。如果有朋友因此了解了一些知识或对Java有了更深层次的理解,从而进行更进一步的学习,那么这篇文章的意义也就达到了。

目录

1.Set系列集合

1.1Set系列集系概述

1.2HashSet元素无序的底层原理:哈希表

1.3实现类:LinkedHashSet

1.4实现类:TreeSet

2.Collection体系的特点、使用场景总结

3.补充知识:可变参数

4.补充知识:集合工具类Collections

5.Collection体系的综合案例

6.Map集合体系

6.1Map集合的概述

6.2Map集合体系特点

6.3Map集合常用API

6.4Map集合的遍历方式一:键找值

6.5Map集合的遍历方式二:键值对

6.6Map集合的遍历方式三:lambda表达式

6.7Map集合的实现类HashMap、LinkedHashMap、TreeMap

6.7.1HashMap的特点和底层原理

6.7.2LinkedHashMap集合概述和特点

6.7.3TreeMap集合概述和特点

7.补充知识:集合的嵌套


集合(Set、Collections、Map、集合嵌套)

1.Set系列集合

1.1Set系列集系概述

Set系列集合特点

无序:存取顺序不一致

不重复:可以去除重复

无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素。

Set集合实现类特点

HashSet:无序、不重复、无索引。

LinkedHashSet:有序、不重复、无索引(并不是真的无索引,而是对外没有提供索引相关API)。

TreeSet:排序(默认自动升序排序)、不重复、无索引。

Set集合的功能上基本上与Collection的API一致。

1.2HashSet元素无序的底层原理:哈希表

HashSet底层原理

HashSet集合底层采取哈希表存储的数据。

哈希表是一种对于增删改查数据性能都较好的结构。

哈希表的组成

JDK8之前的,底层使用数组+链表组成

JDK8开始后,底层采用数组+链表+红黑树组成。

在了解哈希表之前需要先理解哈希值的概念。

哈希值

是JDK根据对象的地址,按照某种规则算出来的int类型的数值。

Object类的API

publicinthashCode():返回对象的哈希值

对象的哈希值特点

同一个对象多次调用hashCode()方法返回的哈希值是相同的

默认情况下,不同对象的哈希值是不同的。

哈希表的详细流程

①创建一个默认长度16,默认加载因为0.75的数组,数组名table。

②根据元素的哈希值跟数组的长度求余计算出应存入的位置(哈希算法)。

③判断当前位置是否为null,如果是null直接存入,如果位置不为null,表示有元素,则调用equals方法比较属性值,如果一样,则不存,如果不一样,则存入数组。

JDK7新元素占老元素位置,指向老元素,JDK8中新元素挂在老元素下面。

④当数组存满到16*0.75=12时,就自动扩容,每次扩容原先的两倍。

JDK1.8版本开始HashSet原理解析

底层结构:哈希表(数组、链表、红黑树的结合体)

当挂在元素下面的数据过多时,查询性能降低,从JDK8开始后,当链表长度超过8的时候,自动转换为红黑树,进一步提高了操作数据的性能。

案例:Set集合去重复

需求:创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合,要求:学生对象的成员变量值相同,我们就认为是同一个对象

分析:

①定义学生类,创建HashSet集合对象,创建学生对象。

②把学生添加到集合。

③在学生类中重写两个方法,hashCode()和equals(),自动生成即可。

④遍历集合(增强for)。

示例代码如下:

Student类

public class Student {private String name;private int age;private char sex;public Student() {}public Student(String name, int age, char sex) {this.name = name;this.age = age;this.sex = sex;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public char getSex() {return sex;}public void setSex(char sex) {this.sex = sex;}/*** 两个对象中每个字段内容相同即返回true** @param o* @return*/@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == nul|| getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age &&sex == student.sex &&Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age, sex);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", sex=" + sex +'}';}
}

测试类

public class SetDemo2 {public static void main(String[] args) {/*需求:创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合要求:学生对象的成员变量值相同,我们就认为是同一个对象*/Set<Student> sets = new HashSet<>();sets.add(new Student("张三", 18, '男'));sets.add(new Student("李四", 20, '男'));sets.add(new Student("李四", 20, '男'));System.out.println(sets); // [Student{name='李四', age=20, sex=男}, Student{name='张三', age=18, sex=男}]// Set集合去重复原理:先判断哈希值,再判断equals// 若没有重写hasCode()与equals()方法,打印结果为[Student{name='李四', age=20, sex=男}, Student{name='张三', age=18, sex=男}, Student{name='李四', age=20, sex=男}]// 没有去重复,两个对象地址不同,哈希值就不同,存储位置也就不同}
}

自动生成重写hasCode()与equals()方法步骤如下。

①如下图所示,在Student类中空白处点击【鼠标右键】,选择【生成】。

②如下图所示,在弹出的页面中选择【equals()和hasCode()】。

③在弹出的页面中依次选择【下一个】,最后选择【完成】,如下图所示,即可自动生成重写的equals()与hasCode()方法。

1.3实现类:LinkedHashSet

LinkedHashSet集合概述和特点

有序、不重复、无索引。

这里的有序指的是保证存储和取出的元素顺序一致。

        原理:底层数据结构依然是哈希表,只是每个元素又额外的多了一个双链表记录存储顺序。

1.4实现类:TreeSet

TreeSet集合概述和特点

不重复、无索引、可排序。

可排序:按照元素的大小默认升序(从小到大)排序。

TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好。

注意:TreeSet集合是一定要排序的,可以将元素按照指定的规则进行排序。

TreeSet集合默认的规则

对于数值类型:Integer , Double,官方默认按照大小进行升序排序。

对于字符串类型:默认按照首字符的编号升序排序。

对于自定义类型如Student对象,TreeSet无法直接排序。

        注:想要使用TreeSet存储自定义类型,需要制定排序规则。

自定义排序规则

TreeSet集合存储对象的的时候有2种方式可以设计自定义比较规则。

方式一:让自定义类(如学生类)实现Comparable接口重写里面的compareTo方法来制定比较规则。

方式二:TreeSet集合有参数构造器,可以设置Comparator接口对应的比较器对象,来制定比较规则。

关于返回值的规则:

如果认为第一个元素大于第二个元素返回正整数即可。

如果认为第一个元素小于第二个元素返回负整数即可。

如果认为第一个元素等于第二个元素返回0即可,此时Treeset集合只会保留一个元素,认为两者重复。

示例代码如下:

Apple类

public class Apple implements Comparable<Apple> {private String name;private String color;private double price;private int weight;public Apple() {}public Apple(String name, String color, double price, int weight) {this.name = name;this.color = color;this.price = price;this.weight = weight;}@Overridepublic String toString() {return "Apple{" +"name='" + name + '\'' +", color='" + color + '\'' +", price=" + price +", weight=" + weight +'}';}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}public int getWeight() {return weight;}public void setWeight(int weight) {this.weight = weight;}/*** 方式一:类自定义比较规则** @param o* @return*/@Overridepublic int compareTo(Apple o) {// 按照重量从小到大排序
//        return this.weight - o.weight; // "金元帅"与"金冠"的"weight"属性都为500,TreeSet集合在排序时认为二者重复,会删去一个return this.weight - o.weight >= 0 ? 1 : -1; // 去掉二者相等返回0的情况,保证"weight"相等的数据都会得到保留}}

测试类

public class SetDemo3 {public static void main(String[] args) {// 存储数值类型:Integer为例Set<Integer> sets = new TreeSet<>(); // 不重复 无索引 可排序sets.add(10);sets.add(23);sets.add(7);System.out.println(sets); // [7, 10, 23]// 存储字符串类型:StringSet<String> sets2 = new TreeSet<>();sets2.add("Java");sets2.add("java");sets2.add("李四");sets2.add("HTML");sets2.add("Zed");System.out.println(sets2); // [HTML, Java, Zed, java, 李四]// 存储自定义类型:Student为例Set<Apple> sets3 = new TreeSet<>();sets3.add(new Apple("红富士", "红色", 9.9, 500));sets3.add(new Apple("青苹果", "青色", 12.5, 300));sets3.add(new Apple("金元帅", "金色", 20, 600));sets3.add(new Apple("金冠", "金色", 25.5, 500));// 如果没有制定排序规则直接打印集合,则无法排序,会报错System.out.println(sets3);// [Apple{name='青苹果', color='青色', price=12.5, weight=300}, Apple{name='红富士', color='红色', price=9.9, weight=500},// Apple{name='金冠', color='金色', price=25.5, weight=500}, Apple{name='金元帅', color='金色', price=20.0, weight=600}]System.out.println("-----------");
/*        Set<Apple> apples = new TreeSet<>(new Comparator<Apple>() {// 方式二:集合自带比较器对象进行规则制定// 注:如果TreeSet集合存储的对象有实现比较规则,集合也自带比较器,默认使用集合自带的比较器排序。@Overridepublic int compare(Apple o1, Apple o2) {
//                return o1.getWeight() - o2.getWeight(); // "金元帅"与"金冠"的"weight"属性都为500,TreeSet集合在排序时认为二者重复,会删去一个return o1.getWeight() - o2.getWeight() >= 0 ? 1 : -1; // 去掉二者相等返回0的情况,保证"weight"相等的数据都会得到保留}});*/// lambda表达式简化Set<Apple> apples = new TreeSet<>((o1, o2) -> o1.getWeight() - o2.getWeight() >= 0 ? 1 : -1);apples.add(new Apple("红富士", "红色", 9.9, 500));apples.add(new Apple("青苹果", "青色", 12.5, 300));apples.add(new Apple("金元帅", "金色", 20, 600));apples.add(new Apple("金冠", "金色", 25.5, 500));System.out.println(apples);// [Apple{name='青苹果', color='青色', price=12.5, weight=300}, Apple{name='红富士', color='红色', price=9.9, weight=500},// Apple{name='金冠', color='金色', price=25.5, weight=500}, Apple{name='金元帅', color='金色', price=20.0, weight=600}]}
}

        注:如果TreeSet集合存储的对象有实现比较规则,集合也自带比较器,默认使用集合自带的比较器排序。

2.Collection体系的特点、使用场景总结

1.如果希望元素可以重复,又有索引,索引查询要快?

        用ArrayList集合,基于数组的。(用的最多)

2.如果希望元素可以重复,又有索引,增删首尾操作快?

        用LinkedList集合,基于链表的。

3.如果希望增删改查都快,但是元素不重复、无序、无索引。

        用HashSet集合,基于哈希表的。

4.如果希望增删改查都快,但是元素不重复、有序、无索引。

        用LinkedHashSet集合,基于哈希表和双链表。

5.如果要对对象进行排序。

        用TreeSet集合,基于红黑树。后续也可以用List集合实现排序。

3.补充知识:可变参数

可变参数概述

可变参数用在形参中可以接收多个数据。

可变参数的格式:数据类型...参数名称

可变参数的作用

传输参数非常灵活,方便。可以不传输参数,可以传输1个或者多个,也可以传输一个数组

        可变参数在方法内部本质上就是一个数组。

可变参数的注意事项:

1.一个形参列表中可变参数只能有一个。

2.可变参数必须放在形参列表的最后面。

示例代码如下:

public class MethodDemo {public static void main(String[] args) {// 1.不传参数sum();// 2.传输1个参数sum(10);// 3.传输多个参数sum(10, 20, 50);// 4.传输数组sum(new int[]{10, 20, 30});}public static void sum(int... nums) {// 可变参数在方法内部实际上就是一个数组System.out.println("元素个数:" + nums.length);System.out.println("元素内容:" + Arrays.toString(nums));System.out.println("-----------");}
}

程序运行结果如下:

元素个数:0

元素内容:[]

-----------

元素个数:1

元素内容:[10]

-----------

元素个数:3

元素内容:[10, 20, 50]

-----------

元素个数:3

元素内容:[10, 20, 30]

-----------

4.补充知识:集合工具类Collections

Collections集合工具类概述

java.utils.Collections:是集合工具类

作用:Collections并不属于集合,是用来操作集合的工具类。

Collections常用的API

方法名

说明

public static <T> boolean addAll(Collection<? super T> c, T... elements)

给集合对象批量添加元素

public static void shuffle(List<?> list)

打乱List集合元素的顺序

Collections排序相关API

使用范围:只能对于List集合的排序。

        注:Shift + F6 一键修改所有出现的该参数名称

具有值特性的类型对象排序

方法名

说明

public static <T> void sort(List<T> list)

将集合中(具有值特性的)元素按照默认规则(从小到大)排序

注意:本方式不可以直接对自定义类型的List集合排序,除非自定义类型实现了比较规则Comparable接口。

自定义类型对象排序

方法名

说明

public static <T> void sort(List<T> list,Comparator<? super T> c)

将集合中元素按照指定规则排序

在自定义类型中实现比较规则Comparable接口

示例代码如下:

Apple类

public class Apple implements Comparable<Apple> {private String name;private String color;private double price;private int weight;public Apple() {}public Apple(String name, String color, double price, int weight) {this.name = name;this.color = color;this.price = price;this.weight = weight;}@Overridepublic String toString() {return "Apple{" +"name='" + name + '\'' +", color='" + color + '\'' +", price=" + price +", weight=" + weight +'}';}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}public int getWeight() {return weight;}public void setWeight(int weight) {this.weight = weight;}/*** 方式一:类自定义比较规则** @param o* @return*/@Overridepublic int compareTo(Apple o) {// 按照重量从小到大排序return this.weight - o.weight; // List集合允许重复,不会删去重复元素,即相等也无妨}
}

测试类

public class CollectionsDemo1 {public static void main(String[] args) {List<String> names = new ArrayList<>();// 1.   public static <T> boolean addAll(Collection<? super T> c, T... elements) 给集合对象批量添加元素
//        names.add("张三");
//        names.add("李四");
//        names.add("王五");// 添加数据比较麻烦,使用addAll方法批量添加数据Collections.addAll(names, "张三", "李四", "王五");System.out.println(names); // [张三, 李四, 王五]// 2.   public static void shuffle(List<?> list) 打乱List集合元素的顺序Collections.shuffle(names);System.out.println(names); // [李四, 王五, 张三]// 3.   public static <T> void sort(List<T> list) 将集合中(具有值特性的)元素按照默认规则(从小到大)排序List<Integer> list = new ArrayList<>();Collections.addAll(list, 2, 5, 19, 10, 3);Collections.sort(list);System.out.println(list); // [2, 3, 5, 10, 19]// 自定义类型对象排序// ①在自定义类型中实现比较规则Comparable接口List<Apple> apples = new ArrayList<>();apples.add(new Apple("红富士", "红色", 9.9, 500));apples.add(new Apple("青苹果", "青色", 12.5, 300));apples.add(new Apple("金元帅", "金色", 20, 600));apples.add(new Apple("金冠", "金色", 25.5, 500));Collections.sort(apples);System.out.println(apples);// [Apple{name='青苹果', color='青色', price=12.5, weight=300}, Apple{name='红富士', color='红色', price=9.9, weight=500},// Apple{name='金冠', color='金色', price=25.5, weight=500}, Apple{name='金元帅', color='金色', price=20.0, weight=600}]// ②通过重写比较器对象中的比较方法,自定义比较规则// 4.   public static <T> void sort(List<T> list,Comparator<? super T> c) 将集合中元素按照指定规则排序
//        Collections.sort(apples, new Comparator<Apple>() {
//            @Override
//            public int compare(Apple o1, Apple o2) {
//                // 根据价格升序排序
//                return Double.compare(o1.getPrice(), o2.getPrice()); // public static int compare(double d1, double d2)方法比较两个double类型数据,返回1或-1
//            }
//        });// 使用lambda表达式简化匿名内部类的写法Collections.sort(apples, (o1, o2) -> Double.compare(o1.getPrice(), o2.getPrice())); // public static int compare(double d1, double d2)方法比较两个double类型数据,返回1或-1System.out.println(apples); // 重写比较器对象中的比较方法方式优先级高于自定义类型中实现比较规则Comparable接口,优先匹配重写比较器对象中的比较方法方式// [Apple{name='红富士', color='红色', price=9.9, weight=500}, Apple{name='青苹果', color='青色', price=12.5, weight=300},// Apple{name='金元帅', color='金色', price=20.0, weight=600}, Apple{name='金冠', color='金色', price=25.5, weight=500}]}
}

        注:重写比较器对象中的比较方法方式优先级高于自定义类型中实现比较规则Comparable接口,优先匹配重写比较器对象中的比较方法方式。

5.Collection体系的综合案例

案例—斗地主游戏

需求:在启动游戏房间的时候,应该提前准备好54张牌,完成洗牌、发牌、牌排序、逻辑。

分析:

①:当系统启动的同时需要准备好数据,可以使用静态代码块来完成。

②:洗牌就是打乱牌的顺序。

③:定义三个玩家、依次发出51张牌。

④:给玩家的牌进行排序(拓展)。

⑤:输出每个玩家的牌数据。

示例代码如下:

Card类

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;}@Overridepublic String toString() {return color + size;}// getter、setter
}

测试类

public class GameDemo {// 定义一个静态的集合存储54张牌public static List<Card> allCards = new ArrayList<>();static int index; // 记录扑克牌权值大小// 定义静态代码块初始化牌的数据static {// 初始化数据:点数确定、类型确定,使用数组String[] sizes = {"3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "A", "2"};// 初始化数据:花色数目确定、类型确定,使用数组String[] colors = {"♥", "♦", "♣", "♠"};for (String color : colors) {index = 0; // 表示sizes数组中的"3"权值最小,仅表示大小关系,不一定是0,其他数目也可以for (String size : sizes) {index++; // 每向后查询一次,扑克牌权值大小+1,代表具有更大的效力// 封装成一个牌对象Card card = new Card(size, color, index);// 将牌对象封装到集合容器中allCards.add(card);}}// 此时index代表数字中效力最大的"2"的权值,大王>小王>2// 将大、小王牌对象封装到集合容器中allCards.add(new Card("", "小王", ++index));allCards.add(new Card("", "大王", ++index));System.out.println("新牌:" + allCards);}public static void main(String[] args) {// 洗牌—打乱扑克牌顺序Collections.shuffle(allCards);System.out.println("洗牌后:" + allCards);// 定义3个ArrayList集合容器,代表3位玩家手中的扑克牌List<Card> cardList1 = new ArrayList<>();List<Card> cardList2 = new ArrayList<>();List<Card> cardList3 = new ArrayList<>();// 发牌—在牌堆中分别给3位玩家发17张牌,剩余3张作为底牌for (int i = 0; i < allCards.size() - 3; i++) {Card card = allCards.get(i);// 轮循:第n张牌发给第1位玩家;第n + 1张牌发给第2位玩家;第n + 3张牌发给第3位玩家// 通过取余的方式实现switch (i % 3) {case 0:cardList1.add(card);break;case 1:cardList2.add(card);break;case 2:cardList3.add(card);break;default:System.out.println("系统错误!");}}// 拿到3张底牌// 通过 List<E> subList(int fromIndex, int toIndex)方法(左闭右开)把最后3张牌截取为子集合List<Card> lastThreeCards = allCards.subList(allCards.size() - 3, allCards.size());// 模拟抢地主Scanner sc = new Scanner(System.in);System.out.println("请输入1、2、3第几位玩家是地主:");int landlord = sc.nextInt();// 为地主玩家分配底牌switch (landlord) {case 1:cardList1.addAll(lastThreeCards);break;case 2:cardList2.addAll(lastThreeCards);break;case 3:cardList3.addAll(lastThreeCards);break;default:System.out.println("系统错误!");}// 给玩家手牌排序sortCards(cardList1);sortCards(cardList2);sortCards(cardList3);// 将玩家手牌输出System.out.println("玩家1:" + cardList1);System.out.println("玩家2:" + cardList2);System.out.println("玩家3:" + cardList3);System.out.println("底牌:" + lastThreeCards);}/*** create by: 全聚德在逃烤鸭、* description: 扑克牌排序* create time: 2022/5/6 0006 16:23** @param cardList* @return void*/private static void sortCards(List<Card> cardList) {// Collections工具类的 public static <T> void sort(List<T> list, Comparator<? super T> c)方法与List类中的default void sort(Comparator<? super E> c)方法完全相同Collections.sort(cardList, (o1, o2) -> o2.getIndex() - o1.getIndex()); // 降序排列}
}

        注:Collections工具类的 public static <T> void sort(List<T> list, Comparator<? super T> c)方法与List类中的default void sort(Comparator<? super E> c)方法完全相同

6.Map集合体系

6.1Map集合的概述

Map集合概述和使用

Collection是单列集合体系,Map集合是一种双列集合,每个元素包含两个数据。

Map集合的每个元素的格式:key=value(键值对元素)。

Map集合也被称为“键值对集合”。

Map集合整体格式:

Collection集合的格式:[元素1,元素2,元素3..]

Map集合的完整格式:{key1=value1 , key2=value2 , key3=value3 , ...}

6.2Map集合体系特点

Map集合体系如下图所示。

使用最多的Map集合是HashMap,重点掌握HashMap , LinkedHashMap , TreeMap。其他的后续理解。

Map集合体系特点

Map集合的特点都是由键决定的。

Map集合的键是无序,不重复,无索引,值不做要求(可以重复)。

Map集合后面重复的键对应的值会覆盖前面重复键的值。

Map集合的键和值均可以为null。

Map集合实现类特点

HashMap:元素按照键是无序,不重复,无索引,值不做要求。(与Map体系一致)

LinkedHashMap:元素按照键是有序,不重复,无索引,值不做要求。

TreeMap:元素按照建是排序,不重复,无索引的,值不做要求。

示例代码如下:

    public static void main(String[] args) {Map<String, Integer> maps = new HashMap<>();maps.put("Java", 1);maps.put("Nike", 5);maps.put("BENZ", 3);maps.put("Java", 2); // 键"Java"中的值"2"会覆盖之前的值"1"maps.put("Dell", 3);maps.put(null, null); // 键和值均支持nullSystem.out.println(maps); // {Nike=5, BENZ=3, null=null, Java=2, Dell=3}}

6.3Map集合常用API

Map集合

Map是双列集合的祖宗接口,它的功能是全部双列集合都可以继承使用的。

Map集合常用API

方法名

说明

V put(K key,V value)

根据键添加元素值,返回该键对应的原值,

若没有原值(添加新元素)则返回null

V get(Object key)

根据键获取对应值

V remove(Object key)

根据键删除键值对元素,

返回被删除键对应的值

void clear()

清空集合

boolean containsKey(Object key)

判断集合是否包含指定的键

boolean containsValue(Object value)

判断集合是否包含指定的值

boolean isEmpty()

判断集合是否为空

int size()

集合的长度,也就是集合中键值对的个数

Set<K> keySet()

获取全部键的集合

Collection<V> values()

获取全部值的集合,不会删去重复的值

void putAll(Map<? extends K, ? extends V> m)

拷贝其他map集合,后面重复的键对应的值会覆盖前面重复键的值

示例代码如下:

    public static void main(String[] args) {Map<String, Integer> maps = new HashMap<>();maps.put("iphoneX", 10);maps.put("娃娃", 20);maps.put("iphoneX", 100); // 键"iphoneX"中的值"100"会覆盖之前的值"10"maps.put("HUAWEI", 100);maps.put("生活用品", 10);maps.put("手表", 10);// {手表=10, 生活用品=10, iphoneX=100, 娃娃=20, HUAWEI=100}System.out.println(maps);// 1.   void clear() 清空集合
//        maps.clear();
//        System.out.println(maps); // {}// 2.   boolean isEmpty() 判断集合是否为空
//        boolean isEmpty = maps.isEmpty();
//        System.out.println(isEmpty); // true// 3.   V get(Object key) 根据键获取对应值Integer value = maps.get("HUAWEI");System.out.println(value); // 100System.out.println(maps.get("Nike")); // nu 若没有该键,取出的值为"null"// 4.   V remove(Object key) 根据键删除键值对元素,返回被删除键对应的值Integer value2 = maps.remove("iphoneX");System.out.println(value2); // 100// 5.   boolean containsKey(Object key) 判断集合是否包含指定的键boolean isContainsKey = maps.containsKey("手表");System.out.println(isContainsKey); // trueSystem.out.println(maps.containsKey("iphoneX")); // false// 6.   boolean containsValue(Object value) 判断集合是否包含指定的值boolean isContainsValue = maps.containsValue(100);System.out.println(isContainsValue); // trueSystem.out.println(maps.containsValue(50)); // false// 7.   Set<K> keySet()   获取全部键的集合Set<String> keys = maps.keySet();System.out.println(keys); // [手表, 生活用品, 娃娃, HUAWEI]// 8.   Collection<V> values() 获取全部值的集合Collection<Integer> values = maps.values();System.out.println(values); // [10, 10, 20, 100]    不会删去重复的值// 9.   int size() 集合的长度,也就是集合中键值对的个数System.out.println(maps.size()); // 4// 10.  V put(K key,V value) 根据键添加元素值,返回该键对应的原值,若没有原值(添加新元素)则返回nullInteger putValue = maps.put("HTML", 1);Integer putValue2 = maps.put("娃娃", 1);System.out.println(putValue); // nullSystem.out.println(putValue2); // 20System.out.println(maps); // {手表=10, 生活用品=10, HTML=1, 娃娃=1, HUAWEI=100}// 11.   void putAll(Map<? extends K, ? extends V> m) 拷贝其他map集合Map<String, Integer> maps1 = new HashMap<>();maps1.put("Java", 1);maps1.put("HTML", 1);Map<String, Integer> maps2 = new HashMap<>();maps2.put("HTML", 2);maps2.put("MySQL", 3);maps1.putAll(maps2); // 键"HTML"中的值"2"会覆盖原值"1"System.out.println(maps1); // {Java=1, MySQL=3, HTML=2}}

6.4Map集合的遍历方式一:键找值

Map集合的遍历方式一:键找值

先获取Map集合的全部键的Set集合。

遍历键的Set集合,然后通过键提取对应值。

示例代码如下:

    public static void main(String[] args) {Map<String, Integer> maps = new HashMap<>();maps.put("iphoneX", 10);maps.put("娃娃", 20);maps.put("HUAWEI", 100);maps.put("生活用品", 10);maps.put("手表", 10);System.out.println(maps);// 1.拿到集合的全部键Set<String> keys = maps.keySet();// 2.遍历每一个键,根据键提取值for (String key : keys) {int value = maps.get(key);System.out.println(key + "-->" + value);}}

程序运行结果如下:

{手表=10, 生活用品=10, iphoneX=10, 娃娃=20, HUAWEI=100}

手表-->10

生活用品-->10

iphoneX-->10

娃娃-->20

HUAWEI-->100

6.5Map集合的遍历方式二:键值对

Map集合的遍历方式二:键值对

先把Map集合转换成Set集合,Set集合中每个元素都是键值对实体类型

遍历Set集合,然后提取键以及提取值。

键值对涉及到的API

方法名

说明

Set<Map.Entry<K,V>> entrySet()

获取所有键值对对象的集合

K getKey()

获得键

V getValue()

获取值

示例代码如下:

    public static void main(String[] args) {Map<String, Integer> maps = new HashMap<>();maps.put("iphoneX", 10);maps.put("娃娃", 20);maps.put("iphoneX", 100); // 键"iphoneX"中的值"100"会覆盖之前的值"10"maps.put("HUAWEI", 100);maps.put("生活用品", 10);maps.put("手表", 10);// {手表=10, 生活用品=10, iphoneX=100, 娃娃=20, HUAWEI=100}System.out.println(maps);// 1.将map集合转换为Set集合Set<Map.Entry<String, Integer>> entries = maps.entrySet();for (Map.Entry<String, Integer> entry : entries) {String key = entry.getKey();int value = entry.getValue();System.out.println(key + "-->" + value);}}

程序运行结果如下:

{手表=10, 生活用品=10, iphoneX=100, 娃娃=20, HUAWEI=100}

手表-->10

生活用品-->10

iphoneX-->100

娃娃-->20

HUAWEI-->100

6.6Map集合的遍历方式三:lambda表达式

Map集合的遍历方式三:Lambda

得益于JDK 8开始的新技术Lambda表达式,提供了一种更简单、更直接的遍历集合的方式。

Map结合Lambda遍历的API

方法名

说明

default void forEach(BiConsumer<? super K, ? super V> action)

结合lambda遍历Map集合

示例代码如下:

    public static void main(String[] args) {Map<String, Integer> maps = new HashMap<>();maps.put("iphoneX", 10);maps.put("娃娃", 20);maps.put("iphoneX", 100); // 键"iphoneX"中的值"100"会覆盖之前的值"10"maps.put("HUAWEI", 100);maps.put("生活用品", 10);maps.put("手表", 10);// {手表=10, 生活用品=10, iphoneX=100, 娃娃=20, HUAWEI=100}System.out.println(maps);//        maps.forEach(new BiConsumer<String, Integer>() {
//            @Override
//            public void accept(String key, Integer value) {
//                System.out.println(key + "-->" + value);
//            }
//        });// lambda表达式简化匿名内部类maps.forEach((key, value) -> System.out.println(key + "-->" + value));}

Map集合案例:统计投票人数

需求:某个班级80名学生,现在需要组成秋游活动,班长提供了四个景点依次是(A、B、C、D),每个学生 只能选择一个景点,请统计出最终哪个景点想去的人数最多。

分析:

将80个学生选择的数据拿到程序中去。

定义Map集合用于存储最终统计的结果。

遍历80个学生选择的数据,看Map集合中是否存在,不存在存入“数据=1“,存在则其对应值+1。

示例代码如下:

    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);// DACCBAACDAACBACDBCCABBAABAAADBDCBBDCCAACCADDAADCAADADACAADCDBCBCCACACBBBCBADDBCA// 2.定义一个map集合记录最终统计结果Map<Character, Integer> infos = new HashMap<>();// 3.遍历学生选择数据for (int i = 0; i < sb.length(); i++) {// 4.提取当前选择字符char ch = sb.charAt(i);// 5.判断当前Map集合中是否存在这个键if (infos.containsKey(ch)) { // 存在,说明之前出现过该景点选择// 值+1infos.put(ch, infos.get(ch) + 1);} else { // 不存在,说明该景点选择是第一次出现// 值=1infos.put(ch, 1);}}System.out.println(infos); // {A=27, B=16, C=22, D=15}}

6.7Map集合的实现类HashMap、LinkedHashMap、TreeMap

6.7.1HashMap的特点和底层原理

实际上:Set系列集合的底层就是Map实现的,只是Set集合中的元素只要键数据,不要值数据而已。

由键决定:无序、不重复、无索引。HashMap底层是哈希表结构的。

依赖hashCode方法和equals方法保证键的唯一。

如果键要存储的是自定义对象,需要重写hashCode和equals方法。

基于哈希表。增删改查的性能都较好。

6.7.2LinkedHashMap集合概述和特点

由键决定:有序、不重复、无索引。

这里的有序指的是保证存储和取出的元素顺序一致。

原理:底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序。

6.7.3TreeMap集合概述和特点

由键决定特性:不重复、无索引、排序。

排序:按照键数据的大小默认升序(有小到大)排序,只能对键排序。

注意:TreeMap集合一定要排序,可以默认排序,也可以将键按照指定的规则进行排序。

TreeMap和TreeSet底层原理是一样的。

TreeMap集合自定义排序规则有2种:

类实现Comparable接口,重写比较规则。

集合自定义Comparator比较器对象,重写比较规则。

7.补充知识:集合的嵌套

案例—Map集合案例-统计投票人数

需求:某个班级多名学生,现在需要组成秋游活动,班长提供了四个景点依次是(A、B、C、D),每个学 生可以选择多个景点,请统计出最终哪个景点想去的人数最多。

分析:

将80个学生选择的数据拿到程序中去,需要记住每个学生选择的情况。

定义Map集合用于存储最终统计的结果。

示例代码如下:

    public static void main(String[] args) {// 1.拿到80个学生的选择数据// 使用Map集合存储Map<String, List<String>> data = new HashMap<>();// 2.将学生选择数据存储进去List<String> selects1 = new ArrayList<>();Collections.addAll(selects1, "A", "C");data.put("张三", selects1);List<String> selects2 = new ArrayList<>();Collections.addAll(selects2, "B", "C", "D");data.put("李四", selects2);List<String> selects3 = new ArrayList<>();Collections.addAll(selects3, "A", "D");data.put("王五", selects3);System.out.println(data); // {李四=[B, C, D], 张三=[A, C], 王五=[A, D]}// 3.统计每个景点的选择人数Map<String, Integer> maps = new HashMap<>();// 4.获取所有人选择的景点的信息Collection<List<String>> values = data.values();// values = [[B, C, D], [A, C], [A, D]]for (List<String> value : values) { // 遍历data集合中所有的值,每个值均为一个List集合for (String str : value) { // 遍历某个List集合中所有的值,每个值均为一个景点选项// 5.判断当前maps集合中是否存在这个键if (maps.containsKey(str)) { // 存在,说明之前出现过该景点选择// 值+1maps.put(str, maps.get(str) + 1);} else { // 不存在,说明该景点选择是第一次出现// 值=1maps.put(str, 1);}}}System.out.println(maps); // {A=2, B=1, C=2, D=2}}

写在最后:

感谢读完!

纵然缓慢,驰而不息!加油!

Java SE基础知识详解第[12]期—集合(Set、Collections、Map、集合嵌套)相关推荐

  1. Java SE基础知识详解第[13]期—不可变集合、Stream流、异常

    写在前面: 每一个不曾起舞的日子,都是对生命的辜负. 希望看到这里的每一个人都能努力学习,不负韶华,成就更好的自己. 以下仅是个人学习过程中的一些想法与感悟,Java知识博大精深,作为初学者,个人能力 ...

  2. Java SE基础知识详解第[18]期—网络编程(通信)

    写在前面: 每一个不曾起舞的日子,都是对生命的辜负. 希望看到这里的每一个人都能努力学习,不负韶华,成就更好的自己. 以下仅是个人学习过程中的一些想法与感悟,Java知识博大精深,作为初学者,个人能力 ...

  3. Java SE 基础知识

    Java SE 基础知识 1 2 @(Notes)[J2SE, Notes] VICTORY LOVES PREPARATION. 特别说明: 该文档在马克飞象查阅最佳: 本部分知识还在迭代中,欢迎补 ...

  4. Java SE 基础知识体系梳理

    ## Java SE 基础知识体系梳理 ----------day01------------- (1)计算机的体系结构 (2)Java语言的概述 (3)开发环境的搭建和使用 1.计算机的体系结构(常 ...

  5. R语言基础知识详解及概括

    R语言基础知识详解及概括 目录 R语言基础知识详解及概括 R数据可视化示例 R语言进行数据创建

  6. R语言可视化绘图基础知识详解

    R语言可视化绘图基础知识详解 图形参数:字体.坐标.颜色.标签等: 图像符号和线条: 文本属性: 图像尺寸及边界: 坐标轴.图例自定义等: 图像的组合: #install.packages(c(&qu ...

  7. 计算机网络相关知识 参考博客 子网掩码怎么理解 网关及网关的作用 路由器基础知识详解

    子网掩码怎么理解 https://blog.csdn.net/farmwang/article/details/64132723 网关及网关的作用 https://blog.csdn.net/zhao ...

  8. RabbitMQ基础知识详解

    RabbitMQ基础知识详解 2017年08月28日 20:42:57 dreamchasering 阅读数:41890 标签: RabbitMQ 什么是MQ? MQ全称为Message Queue, ...

  9. Android随机点名器,Excel基础知识-详解随机点名器

    说道制作个案例纯粹意外,我多少有点选择恐惧症,为了不在"选择"上纠结,就自己小玩了一下,就用了程序做了个选择器,其实很简单,就是有小时候玩的"点兵点将",稍微变 ...

最新文章

  1. EasyUI入门教程整理与示例代码下载
  2. jdk12 jdk1.8_JDK 12的Files.mismatch方法
  3. OSPF次末节区域配置 201
  4. GitLab 添加组员到指定小组
  5. 别把机器学习和人工智能搞混了! 1
  6. EF Code First Migrations数据库迁移 (转帖)
  7. Mirth Connect 第三章 创建通道
  8. 详细安装 kali 教程
  9. 算法介绍及实现——基于遗传算法改进的BP神经网络算法(附完整Python实现)
  10. 基于Excel的股票回测
  11. 开涛的博客—公众号:kaitao-1234567,一如既往的干货分享
  12. 如何为word增加页码,且第一页不显示页码?
  13. HTML+CSS实现按钮手风琴效果 | 青训营笔记
  14. Unix/Linux编程:getcontext、setcontext
  15. C/C++黑魔法-利用include宏读文件
  16. ubuntu18.04 安装mx250显卡驱动(超详细)
  17. 图文详解丨iOS App上架全流程及审核避坑指南
  18. 最新PHP/SG11扩展解密视频教程分享
  19. 揭秘-Android刷量有多容易
  20. 哈工大计算机学院2020复试分数线,2020考研分数线:哈尔滨工业大学2020年复试基本分数线公布!...

热门文章

  1. ChatGPT登上Time封面!这场竞赛,OpenAI赌赢了
  2. NYOJ_613_免费馅饼
  3. 大数高精度加减、乘除、开根(C++版全套最详细、最易懂)
  4. Java:Java实现简单闹钟设计
  5. 最近很多人问我:saiku下载不下来
  6. 项目经理的能力模型和能力提升的方法
  7. EVOLAB | 再度解析共识机制:POW
  8. 2002 计算球体体积
  9. 手把手建项目 PrimeNG安装使用
  10. vue项目中,js根据文件名后缀,判断文件图片、视频、文档、pdf等类型的方法