Set系列集合
一.Set系列集合集概述
1Set系列集合特点:
(1)无序:存取顺序不一致
(2)不重复:可以去除重复
(3)无索引:没有带索引的方法,所以不能使用普通for循环比那里,也不能通过索引来获取元素
2Set系列实现类特点
(1)HashSet:无序、不重复、无索引
(2)LinkedHashSet:有序、不重复、无索引
(3)TreeSet:排序、不从负、无索引
3Set集合的功能上基本与Collection的API一致
4总结:
(1)Set系列集合的特点
(I)无序、不重复、无索引
(2)Set集合的实现类特点
(I)HashSet:无序、不重复、无索引
(II)LinkedHashSet:有序、不重复、无索引
(III)TreeSet:排序、不从负、无索引
package com.itheima_d1_set;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
public class SetDemo1 {
public static void main(String[] args) {
//看看Set系列集合的特点,HashSet LinkedHashSET TreeSet
Set<String> sets = new HashSet<>(); //一行经典代码
//<String> sets = new LinkedHashSet<>(); //有序 不重复 无索引
sets.add("Java");
sets.add("MySQL");
sets.add("MySQL");
sets.add("Java");
sets.add("Java");
sets.add("HTML");
sets.add("HTML");
sets.add("SpringBoot");
sets.add("SpringBoot");
System.out.println(sets);
}
}
二.HashiSet元素无序的底层原理:哈希表
1HashSet底层原理
(1)HashSet集合底层采取哈希表存储的数据
(2)哈希表是一种对于增删改查数据性能都较好的结构。
2哈希表的组成
(1)JDK8之前,底层使用数组+链表组成
(2)JDK8开始后,底层采用数组+链表+红黑树组成
3哈希值
(1)是JDK根据对象的地址,按照某种规则算出来的int类型的数值
4Object类的API
(1)public int hashCode();
5对象的哈希值特点
(1)同一个对象多次调用hashCode()方法返回的哈希值是相同的
(2)默认情况下,不同对象的哈希值是不同的
6HashSet1.7版本原理解析:数组+链表+(结合哈希算法)
Set<String> sets = new HashSet<>();
①创建一个默认长度16的数组,数组名table
②根据元素的哈希值跟数组的长度求余计算出应存入的位置(哈希算法)
③判断当前位置是否为null,如果是null直接存入
④如果位置补位null,表示有元素,则调用equals方法比较
⑤如果一样,则不存,如果不一样,则存入数组
-JDK7新元素占老元素位置,指向老元素
-JDK8中新元素挂在老元素下面
7结论:哈希表是一种对于增删改查数据性能都较好的结构。
8JDK1.8版本开始HashSet原理解析
(1)底层结构:哈希表(数组、链表、红黑树的结合体)
(2)当挂在元素下面的数据过多时,查询性能降低,从JDK8开始后,当链表长度超过8的时候,自动转换为红黑树
9总结
(1)Set集合的底层原理是什么样的
(I)JDK8之前的,哈希表:底层使用数组+链表组成
(II)JDK8开始后,哈希表:底层采用数组+链表+红黑树组成
(2)哈希表的详细流程
(I)创建一个默认长度16,默认加载因为0.75的数组,数组名table
(II)根据元素的哈希值跟数组的长度计算出应存入的位置
(III)判断当前位置是否为null,如果是null直接存入,如果位置不为null,表示有元素,则调用equals方法比较属性值,如果一样,则不存,如果不一样,则存入数组
(IV)当数组存满到16*0.75=12时,就自动扩容,每次扩容原先的两倍
三.HashSet元素去重复的底层原理
案例:创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合,要求:学生对象的成员变量值相同,我们就认为是同一个对象
分析:①定义学生类,创建HashSet集合对象,创建学生对象
②把学生添加到集合
③在学生类中重写两个方法,hashCode()和equals(),自动生成即可
④遍历集合(增强for)
总结:1如果希望Set集合认为2个内容相同的对象时重复的应该怎么办?
重写对象的hashCode和equals方法
package com.itheima_d1_set;
import java.util.Objects;
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
'}';
}
/**
* 只要2个对象一样,结果一定是true
* @param o
* @return
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && sex == student.sex && Objects.equals(name, student.name);
}
/**
*
* @return
*/
@Override
public int hashCode() {
return Objects.hash(name, age, sex);
}
}
package com.itheima_d1_set;
import java.util.HashSet;
import java.util.Set;
/*
目标:让Set集合把从夫内容的对象去掉一个(去重复)
*/
public class SetDemo03 {
public static void main(String[] args) {
//Set集合去重复原因:先判断哈希值 在判断equals
Set<Student> sets = new HashSet<>();
Student s1 = new Student("鲁智深", 18 , '男');
Student s2 = new Student("匿蝶", 25 , '女');
Student s3 = new Student("匿蝶", 25 , '女');
sets.add(s1);
sets.add(s2);
sets.add(s3);
System.out.println(sets);
}
}
package com.itheima_d1_set;
import java.util.HashSet;
import java.util.Set;
public class SetDemo04 {
public static void main(String[] args) {
//看看Set系列集合的特点,HashSet LinkedHashSET TreeSet
Set<String> sets = new HashSet<>(); //一行经典代码
//<String> sets = new LinkedHashSet<>(); //有序 不重复 无索引
sets.add("Java");
sets.add("MySQL");
sets.add("MySQL");
sets.add("Java");
sets.add("Java");
sets.add("HTML");
sets.add("HTML");
sets.add("SpringBoot");
sets.add("SpringBoot");
System.out.println(sets);
}
}
四.实现类:LinkedHashSet
1LinkedHashSet集合概述和特点
(1)有序、不重复、无索引
(2)这里的有序指的是保证存储和取出的元素顺序一致
(3)原理:底层数据结构是依然哈希表,只是每个元素有额外的多了一个双链表的机制记录存储的循序
总结:
1LinkedHashSet集合的特点和原理是怎么样的?
(1)有序、不重复、无索引
(2)底层基于哈希表,使用双链表记录添加顺序
五.实现类:TreeSet
1TreeSet集合概述和特点
(1)不重复、无索引、可排序
(2)可排序:按照元素的大小默认升序(由小到大)排序
(3)TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好
(4)注意:TreeSet集合是一定要排序的,可以将元素按照指定的规则进行排序
2TreeSet集合默认的规则
(1)对于数值类型:Interger , Double , 官方默认按照大小进行升序排序
(2)对于字符串类型:默认按照首字符的编号升序排序
(3)对于自定义类型如Student对象,TreeSet无法直接排序
结论:想要使用TreeSet定义类型,需要指定排序规则
3自定义排序规则
(1)TreeSet集合存储对象的时候有2种方式可以设计自定义比较规则
①方式一
(I)让自定义的类(如学生类)实现Comparable接口重写里面的compareTo方法来定制比较规则
②方式二
(II)TreeSet集合有参数构造器,可以设置Comparator接口对应的比较器对象,来定制比较规则
(2)两种方式中,关羽返回值的规则:
(I)如果认为第一个元素大于第二个元素返回正整数即可
(II)如果认为第一个元素小于第二个元素返回负整数即可
(III)如果认为第一个元素等于第二个元素返回0即可,此时Treeset集合只会保留一个元素,认为两者重复
(3)注意:如果TreeSet集合存储的对象有实现比较规则,集合也自带比较器,默认使用集合自带的比较器排序2
4总结:
(1)TreeSet集合的特点是怎么样的?
(I)可排序、不重复、无索引
(II)底层基于红黑树实现排序,增删改查性能较好
(2)TreeSet集合自定义排序规则有几种方法
(I)2种
(II)类实现Comparable接口,重写比较规则
(III)集合自定义Comparator比较器对象,重写比较规则
package com.itheima_d1_set;
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;
}
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;
}
@Override
public String toString() {
return "Apple{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", price=" + price +
", weight=" + weight +
'}';
}
/**
* 方式一:类自定义比较规则
* o1.compareTo(o2)
* @param o
* @return
*/
@Override
public int compareTo(Apple o) {
//按照重量进行比较的
return this.weight - o.weight >=0 ? 1 : -1;
}
}
package com.itheima_d1_set;
import java.util.Collection;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
/**
* 目标:观察TreeSet对于有值特性的数据如何排序
* 学会对自定义类型的对象进行指定规则排序
*/
public class SetDemo05 {
public static void main(String[] args) {
Set<Integer> sets = new TreeSet<>();//不重复 无索引 可排序
sets.add(23);
sets.add(24);
sets.add(12);
sets.add(8);
System.out.println(sets);
Set<String> sets1 = new TreeSet<>();//不重复 无索引 可排序
sets1.add("Java");
sets1.add("Java");
sets1.add("About");
sets1.add("angela");
sets1.add("Python");
sets1.add("UI");
sets1.add("UI");
sets1.add("黑马");
System.out.println(sets1);
System.out.println("=================");
//方式二:集合自带比较器对象进行规则制定
Set<Apple> apples = new TreeSet<>((Apple o1 , Apple o2) -> {
return Double.compare(o2.getPrice() , o1.getPrice());
});
/*{
@Override
public int compare(Apple o1, Apple o2) {
//return o1.getWeight() - o2.getWeight();//升序
//return o2.getWeight() - o1.getWeight();//降序
//注意:浮点型建议直接使用Double.compare进行比较
//return Double.compare(o1.getPrice(), o2.getPrice());//升序
return Double.compare(o2.getPrice() , o1.getPrice());//降序
}
});*/
apples.add(new Apple("红富士" , "红色" , 9.9 , 500));
apples.add(new Apple("青苹果" , "绿色" , 15.9 , 300));
apples.add(new Apple("绿富士" , "青色" , 29.9 , 400));
apples.add(new Apple("黄富士" , "黄色" , 9.8 , 500));
System.out.println(apples);
}
}
六.Collection体系的特点、使用场景总结
1如果希望元素可以重复,又有索引,索引查询要快?
(1)用ArrayList集合,基于数组的。(用的最多)
2如果希望元素可以重复,又有索引,增删首尾操作快
(1)用LinkedList集合,基于链表的
3如果希望增删改查都快,但是元素不重复、无序、无索引
(1)用HashSet集合,基于哈希表的
package com.itheima_d2_params;
import java.util.Arrays;
public class MethodDemo {
public static void main(String[] args) {
sum();//1不传参数
sum(10);//2可以传一个参数
sum(10 , 20 , 30);//3可以传多个参数
sum(new int[]{10 , 20 , 30 , 40 , 50});//4可以传输一个数组
}
/**
* 注意:一个形参列表只能有一个可变参数,可变参数必须放在形参列表的最后面
* @param nums
*/
public static void sum(int...nums){
//public static void sum(int age , int...nums){}
//注意:可变参数在方法内部其实就是一个数组。nums
System.out.println("元素个数:" + nums.length);
System.out.println("元素内容:" + Arrays.toString(nums));
}
}
4如果希望增删改查都快,但是元素不重复、有序、无索引
(1)用LinkedHashSet集合,基于哈希表和双链表
5如果要对对象进行排序
(1)用TreeSet集合,基于红黑树。后续也可以用List集合实现排序
补充知识:可变参数:
1可变参数
(1)可变参数用在形参中可以接收多个数据
(2)可变参数的格式:数据类型...参数名称
2可变参数的作用
(1)传输参数非常灵活,方便。可以不传输参数,可以传输1个或者多个,也可以传输一个数组
3可变参数的注意事项
(1)一个形参列表中可变参数只能有一个
(2)可变参数必须放在形参列表的最后面
补充知识:集合工具类Collections
1Collections集合工具类
(1)java.utils.Collections:是集合工具类
(2)作用:Collections并不属于集合,是用来操作集合的工具类
2Collection常用的API
方法名称 | 说明 |
public static <T> boolean addAll(Collection<? super T> c, T...elements) | 给集合对象批量添加元素 |
public static void shuffle (List<?> list) | 打乱List集合元素的顺序 |
3Collection排序相关API
(1)使用范围:只能对于List集合的排序
①排序方法1:
方法名称 | 说明 |
public static <T> void sort(List<T> list) | 将集合中元素按照默认规则排序 |
注意:本方式不可以直接怼自定义类型的List集合排序,除非自定义类型实现了比较规则Comparable接口
②排序方法2
方法名称 | 说明 |
public static <T> void sort(List<T> list , Comparator<? super T> c) | 将集合中元素按照指定规则排序 |
package com.itheima.d3_collections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CollectionsDemo01 {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
//names.add("楚留香");
//names.add("胡铁花");
//names.add("张无忌");
//names.add("陆小凤");
Collections.addAll(names , "楚留香" , "胡铁花" , "张无忌" , "陆小凤");
System.out.println(names);
//2public static void shuffle(List<?> List) :打乱集合顺序
Collections.shuffle(names);
System.out.println(names);
//3public static void <T> void sort(List<T> list):将集合中元素按照默认规则排序
List<Integer> list = new ArrayList<>();
Collections.addAll(list , 12 , 23 , 2 , 4);
System.out.println(list);
Collections.sort(list);
System.out.println(list);
}
}
package com.itheima.d3_collections;
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;
}
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;
}
@Override
public String toString() {
return "Apple{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", price=" + price +
", weight=" + weight +
'}';
}
/**
* 方式一:类自定义比较规则
* o1.compareTo(o2)
* @param o
* @return
*/
@Override
public int compareTo(Apple o) {
//按照重量进行比较的
return this.weight - o.weight >=0 ? 1 : -1;//List中存储相同大小的元素 会保留!
}
}
package com.itheima.d3_collections;
import java.util.*;
public class CollectionsDemo02 {
public static void main(String[] args) {
List<Apple> apples = new ArrayList<>(); //可以重复!
apples.add(new Apple("红富士" , "红色" , 9.9 , 500));
apples.add(new Apple("青苹果" , "绿色" , 15.9 , 300));
apples.add(new Apple("绿富士" , "青色" , 29.9 , 400));
apples.add(new Apple("黄富士" , "黄色" , 9.8 , 500));
/*Collections.sort(apples);//可以的,Apple类已经重写了比较规则
System.out.println(apples);*/
//方式二:sort方法自带比较器对象
/*Collections.sort(apples, new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
return Double.compare(o1.getPrice(), o2.getPrice());
}
});*/
Collections.sort(apples, ( o1, o2) ->{ return Double.compare(o1.getPrice(), o2.getPrice());});
System.out.println(apples);
}
}
Collection体系的综合案例
斗地主游戏:
需求:在启动游戏房间的时候,应该提前准备好54张牌,完成洗牌、发牌、牌排序、逻辑
分析:①当系统启动的同时需要准备好数据的时候,就可以用静态代码块
②洗牌就是打乱牌的顺序
③定义三个玩家、以此发出51张牌
④给玩家的牌进行排序(扩展)
⑤输出每个玩家的牌数据
package com.itheima.d4_collection_test;
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;
}
}
package com.itheima.d4_collection_test;
import com.sun.source.tree.Tree;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class GameDemo {
/**
*1定义一个静态的集合存储54张牌对象
*/
public static List<Card> allCard = 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存入到集合容器中去
allCard.add(c);
}
}
//8大小王存入集合中去
Card c1 = new Card("" , "小王" , ++index);
Card c2 = new Card("" , "大王" , ++index);
Collections.addAll(allCard , c1 , c2);
System.out.println("新牌:" + allCard);
}
public static void main(String[] args) {
//9洗牌
Collections.shuffle(allCard);
System.out.println("洗牌后:" + allCard);
//10发牌(定义三个玩家,每个玩家的牌也是一个集合容器)
List<Card> linhuchong = new ArrayList<>();
List<Card> jiumozhi = new ArrayList<>();
List<Card> renyingying = new ArrayList<>();
//11开始发牌(从牌集合中发出51张牌给三个玩家,剩余三张作为底牌)
//allCards = [8♣, 3♣, 9♠, Q♦, 4♥, 9♣, Q♠, 2♠, A♠]
for (int i = 0; i < allCard.size() - 3; i++) {
//先拿到当前牌对象
Card c = allCard.get(i);
if (i % 3 ==0){
//请阿冲接牌
linhuchong.add(c);
}else if (i % 3 == 1){
//请阿玖
jiumozhi.add(c);
}else if (i % 3 == 2){
//请盈盈接牌
renyingying.add(c);
}
}
//12最后三张底牌(把最后三张牌截取成一个子集合)
List<Card> lastThreeCards = allCard.subList(allCard.size() - 3 , allCard.size());
//13给玩家的牌排序(从大到小 )
sortCards(linhuchong);
sortCards(jiumozhi);
sortCards(renyingying);
//14输出玩家的牌
System.out.println("阿冲:" + linhuchong);
System.out.println("阿玖:" + jiumozhi);
System.out.println("盈盈:" + renyingying);
System.out.println("三张底牌:" + lastThreeCards);
}
/**
* 给牌排序
* @param cards
*/
private static void sortCards(List<Card> cards) {
//[K♥, A♥, Q♠, 10♥, J♣, Q♦
Collections.sort(cards, (Card o1, Card o2) -> {return o2.getIndex() - o1.getIndex();});
//o1 = K♥
//o2 = A♥
//知道牌的大小,才可以制定规则
}
}
Map集合体系
一.Map集合的概述
1Map集合概述和使用
(1)Map集合是一种双列集合,每个元素包含两个数据
(2)Map集合的每个元素的格式:key=value(键值对元素)
(3)Map集合也被称为“键值对集合”
2Map集合整体格式
(1)Collection集合的格式:[元素1 , 元素2 , 元素3]
(2)Map集合的完整格式:{key1=value1 , key2=value2 , key3=value3, ...}
3Map集合的使用场景之一:购物车系统
分析
(1)购物车提供的四个商品
(2)每个商品对象都一一对应一个购买数量
(3)把商品对象看成是Map集合的建,购买数量看成Map集合的值
{商品1=2 ,商品2=3 ,商品3=2 ,商品4=3}
4总结:
(1)Map集合是什么?使用场景是什么样的?
(I)Map集合是键值对集合
(II)Map集合非常适合做类购物车这样的业务场景
二.Map集合体系特点
1Map集合体系
2Map集合体系特点
(1)Map集合的特点都是由键决定的
(2)Map集合的键是无序的,不重复的,无索引的,值不做要求(可以重复)
(3)Map集合的键对应的值会覆盖前面重复键的值
(4)Map集合的键值对都可以为null
3Map集合实现类特点
(1)HashMap:元素按照键是无序,不重复,无索引,值不做要求。(与Map体系一致)
(2)LinkedHashMap:元素按照键是有序,不重复,无索引,值不做要求
(3)TreeMap:元素按照键是排序,不重复,无索引,值不作要求
package com.itheima.d5_map;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 认识Map体系的特点:按照键无序,不重复,无索引,值不做要求
*/
public class MapDemo1 {
public static void main(String[] args) {
//1创建一个Map集合对象
Map<String , Integer> maps = new LinkedHashMap<>();//一行经典代码
maps.put("鸿星尔克" , 3);
maps.put("枸杞" , 100);
maps.put("Java" , 1);
maps.put("Java" , 100);
maps.put(null , null);
System.out.println(maps);
}
}
三.Map集合常用API
1Map集合
(1)Map是双列集合的祖宗接口,它的功能是全部双列集合都可以继承使用的。
2Map API如下:
方法名称 | 说明 |
V put(K key , V value) | 添加元素 |
V remove(Object key) | 根据键删除键值对元素 |
void clear() | 移除所有的键值对元素 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中键值对的个数 |
package com.itheima.d6_map_traversal;
import java.util.*;
public class MapDemo {
public static void main(String[] args) {
//1添加元素:无序,不重复,无索引
Map<String , Integer> maps = new HashMap<>();
maps.put("iphoneX" , 10);
maps.put("娃娃" , 20);
maps.put("iphoneX" , 100);
maps.put("huawei" , 1000);
maps.put("生活用品" , 10);
maps.put("手表" , 10);
//{huawei=1000, 手表=10, 生活用品=10, iphoneX=100, 娃娃=20}
System.out.println(maps);
//2清空集合
//maps.clear();
System.out.println(maps);
//3判断集合是否为空,为空返回true,反之
System.out.println(maps.isEmpty());
//4根据键获取对应值:public V get(Object key)
Integer Key = maps.get("华为");
System.out.println(Key);
System.out.println(maps.get("生活用品"));//10
System.out.println(maps.get("生活用品2"));
//5根据键删除整个元素(删除键会返回键的值)
System.out.println(maps.remove("iphoneX"));
System.out.println(maps);
//6判断是否包含某个键,包含返回true,反之
System.out.println(maps.containsKey("娃娃"));// true
System.out.println(maps.containsKey("iphoneX")); //false
//7判断是否包含某个值
System.out.println(maps.containsValue(1000));
System.out.println(maps.containsValue(10));
System.out.println(maps.containsValue(22));
//{huawei=1000, 手表=10, 生活用品=10, 娃娃=20}
//8获取全部键的集合:public Set<K> keySet()
Set<String> keys = maps.keySet();
System.out.println(keys);
System.out.println("=======================================");
//9获取全部值的集合:Collection<V> values();
Collection<Integer> values = maps.values();
System.out.println(values);
//10集合的大小
System.out.println(maps.size());
//11合并其他Map集合.(扩展)
Map<String , Integer> map1 = new HashMap<>();
map1.put("java1" , 1);
map1.put("java2" , 100);
Map<String , Integer> map2 = new HashMap<>();
map2.put("java2" , 1);
map2.put("java3" , 100);
map1.putAll(map2);//把map2的元素拷贝一份到map1中去
System.out.println(map1);
System.out.println(map2);
}
}
四.Map集合的遍历方式一:键找值
1Map集合方式一:键找值流程
(1)先获取Map集合的全部键的Set集合
(2)遍历的Set集合,然后通过键提取对应值
2键找值涉及到的API:
方法名称 | 说明 |
Set<K> keySet() | 获取所有键的集合 |
V get(Object key) | 根据键获取值 |
五.Map集合的遍历方式二:键值对
1遍历Map集合方式二:键值对流程
(1)先把Map集合转换成Set集合,Set集合中每个元素都是键值对实体类型了
(2)遍历Set集合,然后提取键以及提取值
2键值对涉及的API:
方法名称 | 说明 |
Set <Map.Entry<K , v>> entrySet() | 获取所有键值对对象的集合 |
K getKey() | 获取键 |
V getValue() | 获取值 |
package com.itheima.d7_map_traversal;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapDemo2 {
public static void main(String[] args) {
Map<String , Integer> maps = new HashMap<>();
//1添加元素:无序,不重复,无索引
maps.put("娃娃", 30);
maps.put("iphoneX" , 100);
maps.put("huawei" , 1000);
maps.put("生活用品" , 10);
maps.put("手表" , 10);
//2把Map集合转换成Set集合
Set<Map.Entry<String, Integer>> entries = maps.entrySet();
//3开始遍历
Set<Map.Entry<String, Integer>> entries1 = entries;
for (Map.Entry<String, Integer> entry : entries) {
String key = entry.getKey();
int value = entry.getValue();
System.out.println(key + "========>" + value);
}
}
}
六.Map集合的遍历方式三:lambda表达式
1Map集合的遍历方式三:Lambda
(1)得益于JDK 8开始的新技术Lambda表达式,提供了一种更简单、更直接的遍历集合的方式
2Map结合Lambda遍历的API
方法名称 | 说明 |
default void forEach(BiConsumer<? super K, ? super V> action) | 结合lambda遍历Map集合 |
流程:
maps = {huawei=1000 , 手表=10 , 生活用品 , iphoneX=100}
map.forEach((k , v) -> {
System.out.println(k + "------>" + V);
});
package com.itheima.d7_map_traversal;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
public class MapDemo03 {
public static void main(String[] args) {
Map<String , Integer> maps = new HashMap<>();
//1添加元素:无序,不重复,无索引
maps.put("娃娃", 30);
maps.put("iphoneX" , 100);
maps.put("huawei" , 1000);
maps.put("生活用品" , 10);
maps.put("手表" , 10);
System.out.println(maps);
//maps = {huawei=1000, 手表=10, 生活用品=10, iphoneX=100, 娃娃=30}
maps.forEach((k, v) ->{
System.out.println(k + "--->" + v);
});
}
}
七.案例:Map集合案例-统计投票人数
需求:某个班80名学生,现在需要组成秋游活动,班长提供了四个景点依次是(A 、V 、C、D),每个学生只能选择一个景点,请统计出最终哪个景点想去的人数最多
分析:将80个学生选择的数据拿到程序中去
定义Map集合用于存储最终统计的结果
遍历80个学生选择的数据,看Map集合中是否存在,不存在存入“数据=1”,存在则其对应值+1
package com.itheima.d8_map_test;
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);
}
}
//6输出集合
System.out.println(infos);
}
}
八.Map集合的实现类HashMap
1HashMap的特点
(1)HashMap是Map里面的一个实现类。特点都是由键决定的:无序、不重复、无索引
(2)没有额外需要学习的特有方法,直接使用Map里面的方法就可以了
(3)HashMap跟HashSet底层原理是一模一样的,都是哈希表结构,只是HashMap的每个元素包含两个值而已
2实际上:Set系列集合的底层就是Map实现的,只是Set集合中的元素只要键数据,不要值数据而已
public HashSet(){
map = new HashMap<>();
}
3总结:
(1)HashMap的特点和底层原理
(I)由键决定:无序、不重复、无索引。HashMap底层是1哈希表结构的。
(II)以来hashCode方法和equals方法保证键的唯一
(III)如果键要存储的是自定义对象,需要重写hashCode和equals方法
(IV)基于哈希表。增删改查性能都较好
package com.itheima.d9_map_impl;
import com.itheima.d1_set.Student;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class HashMapDemo1 {
public static void main(String[] args) {
//Map集合是根据键去重复元素
Map<Student , String> maps = new HashMap<>();
Student s1 = new Student("鲁智深", 18 , '男');
Student s2 = new Student("匿蝶", 25 , '女');
Student s3 = new Student("匿蝶", 25 , '女');
maps.put(s1 , "北京");
maps.put(s2 , "上海");
maps.put(s3 , "广州");
System.out.println(maps);
}
}
九.Map集合的实现类LinkedHashMap
1LinkedHashMap集合概述和特点
(1)由键决定:有序、不重复、无索引
(2)这里的有序指的是保证存储和取出的顺序一致
(3)原理:底层数据结构依然是哈希表,只每个键值对元素又额外的多了一个双链表的机制记录存储的顺序
package com.itheima.d9_map_impl;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeSet;
/**
* 认识Map体系的特点:按照键无序,不重复,无索引,值不做要求
*/
public class LinkedHashDemo2 {
public static void main(String[] args) {
//1创建一个Map集合对象
Map<String , Integer> maps = new LinkedHashMap<>();//一行经典代码
maps.put("鸿星尔克" , 3);
maps.put("枸杞" , 100);
maps.put("Java" , 1);
maps.put("Java" , 100);
maps.put(null , null);
System.out.println(maps);
}
}
十.TreeMap集合概述和特点
1TreeMap集合概述和特点
(1)由键决定特性:不重复、无索引、可排序
(2)可排序:按照数据的大小默认升序(由小到大)排序。只能对键排序。
(3)注意:TreeMap集合是一定要排序的,可以默认排序,也可以将键按照指定的规则进行排序
(4)TreeMap个TreeSet一样底层原理是一样的。
2TreeMap集合自定义排序规则有两种
(1)类实现Comparable接口,重写比较规则
(2)集合自定义Comparator比较器对象,重写比较规则
package com.itheima.d9_map_impl;
import com.itheima.d1_set.Apple;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
public class TreeMapDemo3 {
public static void main(String[] args) {
Map<Integer , String> map1 = new TreeMap<>();
map1.put(13,"王麻子");
map1.put(1,"张三");
map1.put(3,"县长");
System.out.println(map1);
//TreeMap集合自带排序。 可排序 , 不重复(只要大小规则一样就默认重复) 无索引
Map<Apple , String> maps = new TreeMap<>(new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
return Double.compare(o2.getPrice(), o1.getPrice());//按照价格降序排序
}
});
maps.put(new Apple("红富士" , "红色" , 9.9 , 500) , "山东");
maps.put(new Apple("青苹果" , "绿色" , 15.9 , 300) , "上海");
maps.put(new Apple("绿富士" , "青色" , 29.9 , 400) , "八宝山");
maps.put(new Apple("黄富士" , "黄色" , 9.8 , 500) , "湖北");
System.out.println(maps);
}
}
补充知识:集合的嵌套
案例:Map集合阿里-统计投票人数
需求:某个班级多名学生,现在需要组成秋游活动,班长提供了四个景点一次是(A 、B、C、D),每个学生可以选择多个景点,请统计出哪个景点想去的人数最多
分析:①将80个学生选择数据拿到程序中去,需要记住每个学生选择的情况。
②定义Map集合用于存储最终统计的结果
package com.itheima.d9_map_impl;
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);
System.out.println(data);
List<String> selects1 = new ArrayList<>();
Collections.addAll(selects1 , "A" , "B", "C");
data.put("胡桃" , selects1);
System.out.println(data);
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);
//value = {[A , B , C , D] , [B , C , D] , [ A , C ]}
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);
}
}
教学视频资源来自
Java入门基础视频教程,java零基础自学首选黑马程序员Java入门教程(含Java项目和Java真题)_哔哩哔哩_bilibili