概述
集合和数组都是容器。
数组的特点
- 数组定义后,大小固定,数据类型固定
- 在进行增删操作时,需要对元素移位
- 数组可以存储基本数据类型也可以存储引用数据类型的数据
集合的特点
- 集合的长度不确定,可以动态改变长度
- 适合做元素的增删操作
- 集合只能存储引用类型的数据,如果要存储基本类型的数据需要使用包装类
适用场景
数组——适用于数据个数、类型确定
集合——适用于数据个数不确定,需要进行增删操作
集合类的体系结构
- Collection:单列集合,每个元素只包含一个值
- Map:双列集合,每个元素包含两个值(键值对)
Collection体系
Collection集合特点
- List系列集合:添加元素有序、可重复、有索引
- ArrayList
- LinkedList
- Set系列集合:添加元素无序、不可重复、无索引
- HashSet:无序、不重复、无索引
- LinkedHashSet:有序、不重复、无索引
- TreeSet:按照大小默认升序排列,不重复、无索引
- HashSet:无序、不重复、无索引
常用API
-
add() 添加元素
-
addAll(Collection) 将指定集合中的所有元素添加到此集合中
-
clear() 删除所有元素
-
contains(Object) 此集合中包含指定的元素,则返回true
-
isEmpty() 如果此集合不含元素则返回true
-
iterator() 返回此集合元素迭代器
-
remove(Object o) 删除指定元素
package com.spark.study;
import java.util.ArrayList;
import java.util.Collection;
/**
* Test class
* description: Collection常用api
*
* @author Administrator
* @date 2023/3/12
*/
public class Test {
public static void main(String[] args) {
Collection<String> collection = new ArrayList<>();
// 添加元素
collection.add("Java");
collection.add("Python");
collection.add("C++");
collection.add("C#");
collection.add("Java");
System.out.println(collection);
System.out.println("---------------------");
// 将其他集合元素添加到当前集合中
Collection<String> collection2 = new ArrayList<>();
collection2.add("后端");
collection2.add("前端");
collection2.add("测试");
collection2.add("运维");
collection.addAll(collection2);
System.out.println(collection);
System.out.println(collection2);
System.out.println("---------------------");
// 删除所有元素,清空集合
collection2.clear();
System.out.println(collection2);
// 集合是否包含指定元素
System.out.println(collection.contains("java"));
System.out.println(collection.contains("Java"));
// 判断集合是否为空
System.out.println(collection.isEmpty());
System.out.println(collection2.isEmpty());
// 删除指定元素
System.out.println(collection.remove("C#"));
System.out.println(collection);
}
}
集合遍历
集合遍历的方式
① 通过迭代器iterator
② 增强型for循环
既可以遍历集合也可以遍历数组,其内部原理是一个iterator迭代器,遍历集合相当于是迭代器的简化写法,实现iterator接口的类才可以使用迭代器和增强型for循环,Collection接口已经实现了Iterable接口
③ lambda表达式
JDK8引用lambda表达式后,提供了更加简单直接的遍历方式
package com.spark.traversal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* Test class
* description: 集合的遍历方式
*
* @author Administrator
* @date 2023/3/12
*/
public class Test {
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("Web");
list.add("算法");
// 1.迭代器方式
// 获取迭代器对象
Iterator<String> iterator = list.iterator();
// 是否还有元素
while(iterator.hasNext()){
System.out.println(iterator.next());
}
// 2.增强for
for (String s : list) {
System.out.println(s);
}
// 3.lambda表达式
list.forEach((e)->{
System.out.println(e);
});
list.forEach(e-> System.out.println(e));
list.forEach(System.out::println);
}
}
常见数据结构简述
栈
栈的特点:后进先出
数据进栈、出栈都是从栈顶完成,如图所示:
队列
队列的特点:先进先出
数据从队尾入队,从队头出队,如图所示:
数组
数组是一种查询块、增删效率慢的数据模型
查询速度快:查询数据通过地址值和索引定位,查询任意数据消耗时相同。(元素在内存中是连续存储的)
添加效率低:添加元素指定位置,会先将指定位置后的每个元素向后移一位再进行添加
删除效率低:删除指定位置上的元素,还需要将指定位置后的元素向前移一位
链表
链表中的元素在内存中是不连续存储的,每个元素节点包含数据值和下一个元素的地址
链表查询慢。无论查询哪个数据都是从头开始找;增删相对较快。
在A和B之间添加C结点
删除A结点
二叉树
只能有一个根节点,每个节点最多支持两个直接子节点
节点的度:节点拥有的子树的个数,二叉树的度不大于2。叶子节点度为0的节点,也称为终端节点
高度:叶子节点高度为1,叶子节点的父节点高度为2,以此类推,根节点的高度最高
层:根节点在第一层,以此类推
兄弟节点:拥有共同父节点的节点称为兄弟节点
List系列
List系列集合特点
- ArrayList、LinkedList:有序、可重复、有索引
- 有序:存储和取出元素顺序一致
- 有索引:可以通过索引操作元素
- 可重复:存储的元素可以重复
List的实现类的底层原理
- ArrayList底层是基于数组实现的:根据索引定位元素快,增删相对慢
- LinkedList底层是基于双链表实现的:查询元素慢,增删首尾元素快
List集合支持索引操作
-
add(int index,E element) 在此集合中的指定元素插入指定的元素
-
remove(int index) 删除指定索引处的元素,返回被删除的元素
-
set(int index,E element) 修改指定索引的元素,返回被修改的元素
-
get(int index) 返回指定索引处的元素
ArrayList集合索引操作
package com.spark.apistudy;
import java.util.ArrayList;
import java.util.List;
/**
* Test class
* description: TODO
*
* @author Administrator
* @date 2023/3/13
*/
public class Test {
public static void main(String[] args) {
// 创建list集合
List<String> list = new ArrayList<String>();
list.add("java");
list.add("html");
list.add("css");
list.add("js");
list.add("list");
// 在指定索引处添加元素
list.add(2,"python");
System.out.println(list);
// 在指定索引处删除元素
list.remove(4);
System.out.println(list);
// 在指定索引处修改元素
list.set(1,"HTML");
System.out.println(list);
// 返回指定索引处的元素
System.out.println(list.get(3));
}
}
LinkedList
LinkedList底层实现原理是双链表,查询慢,首尾操作快
LinkedList集合特有的功能
-
addFirst(E e) 在该列表的开头插入指定元素
-
addLast(E e) 在指定的元素追加到此列表的末尾
-
E getFirst() 返回此列表的第一个元素
-
E getLast() 返回此列表的最后一个元素
-
E removeFirst() 从此列表中删除并返回第一个元素
-
E removeLast() 从此列表中删除并返回最后一个元素
package com.spark.linkedlist;
import java.util.LinkedList;
/**
* Test class
* description: TODO
*
* @author Administrator
* @date 2023/3/13
*/
public class Test {
public static void main(String[] args) {
// LinkedList底层为双向链表,可以完成队列和栈的操作
// 模拟队列
LinkedList<String> list = new LinkedList<>();
// 入队
list.addLast("1号");
list.addLast("2号");
list.addLast("3号");
System.out.println(list);
// 出队
list.removeFirst();
System.out.println(list);
// 模拟栈
LinkedList<String> list2 = new LinkedList<>();
// 入栈
list2.addFirst("第一颗子弹");
list2.addFirst("第二颗子弹");
// push 底层调用的是addFirst
list2.push("第三颗子弹");
System.out.println(list2);
// 出栈
list2.removeFirst();
System.out.println(list2);
// pop 底层调用的是removeFirst
list2.pop();
System.out.println(list2);
}
}
集合的并发修改异常问题
当从集合中找出某个元素进行删除的时候可能会出现一种并发修改异常问题
java.util.ConcurrentModificationException
package com.spark.exception;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Test class
* description: Test
*
* @author Administrator
* @date 2023/3/13
*/
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
// 准备数据
list.add("java");
list.add("python");
list.add("html");
list.add("html");
list.add("css");
list.add("js");
// 1.使用迭代器删除
Iterator<String> it = list.iterator();
while(it.hasNext()){
String ele = it.next();
if("html".equals(ele)){
//list.remove(ele); //出现并发修改异常
// 使用迭代器的api
it.remove(); // 删除迭代器当前指向的元素
}
}
System.out.println(list);
// 2.使用增强型for循环删除
for (String s : list) {
if("html".equals(s)){
list.remove(s);
}
}
System.out.println(list);
// 3.使用lambda表达式删除
list.forEach((e)->{
if("html".equals(e)){
list.remove(e);
}
});
System.out.println(list);
// 4.for循环删除
for(int i=list.size()-1; i>=0; i--){
if("html".equals(list.get(i))){
list.remove(i);
}
}
System.out.println(list);
}
}
总结
- 迭代器遍历集合并且直接用集合删除元素的时候可能出现
- 增强型for循环和lambda表达式底层调用的都是迭代器,因此也可能出现该问题
- 迭代器进行删除元素时,需要使用迭代器的api进行删除
- for循环删除元素需要进行倒序删除
泛型
概述
泛型是JDK5引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
泛型的格式:<数据类型>
泛型只支持引用数据类型
集合体系的全部接口和实现类都是支持泛型
泛型的好处
- 统一数据类型
- 将运行期间的问题提前到了编译阶段,避免了 强制类型转换可能出现的异常
自定义泛型
(1)自定义泛型类
定义类的同时也定义泛型的类为自定义泛型类
定义格式:
public class MyArrayList<T>{
}
此处泛型变量T也可以写成任意标识,常见的有E、T、K、V等
package com.spark.genericity;
import java.util.ArrayList;
/**
* MyArrayList class
* description: 自定义泛型类
*
* @author Administrator
* @date 2023/3/14
*/
public class MyArrayList<T> {
ArrayList<T> list = new ArrayList<>();
// 添加方法
public void add(T t){
list.add(t);
}
// 删除方法
public void remove(T t){
list.remove(t);
}
public String toString(){
return list.toString();
}
}
package com.spark.genericity;
/**
* Test class
* description: TODO
*
* @author Administrator
* @date 2023/3/14
*/
public class Test {
public static void main(String[] args) {
MyArrayList<String> list = new MyArrayList<>();
list.add("java");
list.add("mysql");
System.out.println(list);
MyArrayList<Integer> list2 = new MyArrayList<>();
list2.add(12);
list2.add(13);
System.out.println(list2);
list.remove("mysql");
list2.remove(13);
System.out.println(list);
System.out.println(list2);
}
}
(2)自定义泛型方法
定义方法的同时也定义泛型的方法为泛型方法
定义格式:
public <T> T getInfo(T t){
}
定义泛型方法模拟toString()方法输出集合中的元素
package com.spark.genericity;
/**
* Test2 class
* description: TODO
*
* @author Administrator
* @date 2023/3/14
*/
public class Test2 {
public static void main(String[] args) {
String [] names = {"小红","小白","小花"};
printArr(names);
Integer [] numbers = {12,2,41,56};
printArr(numbers);
}
public static <T> void printArr(T [] arr){
if(null == arr){
System.out.println(arr);
}else{
StringBuilder stringBuilder = new StringBuilder("[");
for(int i=0;i<arr.length;i++){
stringBuilder.append(arr[i]).append(i==arr.length-1 ? "" : ",");
}
stringBuilder.append("]");
System.out.println(stringBuilder);
}
}
}
(3)自定义泛型接口
定义接口时也定义泛型的接口为自定义泛型接口
定义格式:
public interface Data<T>{
}
定义自定义泛型接口模拟对象的增删改查操作
package com.spark.genericity;
// 自定义泛型接口
public interface Data<T>{
int add(T t);
int remove(int id);
int update(T t);
T query(int id);
}
package com.spark.genericity;
/**
* Student class
* description: 操作学生类
*
* @author Administrator
* @date 2023/3/14
*/
public class Student implements Data<Student>{
@Override
public int add(Student student) {
System.out.println("学生的添加操作");
return 0;
}
@Override
public int remove(int id) {
System.out.println("学生的删除操作");
return 0;
}
@Override
public int update(Student student) {
System.out.println("学生的更新操作");
return 0;
}
@Override
public Student query(int id) {
System.out.println("学生的查询操作");
return null;
}
}
通配符及上下限
通配符:? , ?可以在使用泛型时代表一切类型,E、T、K、V等是在定义泛型时使用
通配符一般与上下限配合使用来限制类型
? extends 类名 ?必须是指定类或者是其子类 泛型上限
? super 类名 ?必须是指定类或者其父类 泛型下限
案例:一场赛车比赛,所有的车都可以进行比赛
package com.spark.genericity;
import java.util.ArrayList;
/**
* Test3 class
* description: TODO
*
* @author Administrator
* @date 2023/3/14
*/
public class Test3 {
// 调用会报错,虽然宝马和奔驰都继承了Car类,
// 但是ArrayList<BMW>、ArrayList<Benz>与ArrayList<Car>是没有关系的
// public static void competition(ArrayList<Car> cars){
//
// }
// 虽然调用不会报错,但是 ? 可以传入任意类型,因此Dog类型也可以传入,不符合逻辑
// public static void competition(ArrayList<?> cars){
//
// }
// 通配符配合上下限使用,限制传入的数据类型
public static void competition(ArrayList<? extends Car> cars){
}
}
class Car{
}
// 宝马车
class BMW extends Car{
}
// 奔驰车
class Benz extends Car{
}
// 狗
class Dog{
}
Set集合
Set集合实现类特点
- HashSet:无序、无重复、无索引
- LinkedHashSet:有序、无重复、无索引
- TreeSet:排序(默认升序)、无重复、无索引
package com.spark.setstudy;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
/**
* Test class
* description: Set接口的实现类特点
*
* @author Administrator
* @date 2023/3/15
*/
public class Test {
public static void main(String[] args) {
// HashSet
Set<String> hashSet = new HashSet<>();
hashSet.add("java");
hashSet.add("java");
hashSet.add("mysql");
hashSet.add("html");
hashSet.add("css");
hashSet.add("css");
System.out.println(hashSet);
// LinkedHashSet
Set<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("java");
linkedHashSet.add("java");
linkedHashSet.add("mysql");
linkedHashSet.add("html");
linkedHashSet.add("css");
linkedHashSet.add("css");
System.out.println(linkedHashSet);
// TreeSet
Set<Integer> treeSet = new TreeSet<>();
treeSet.add(15);
treeSet.add(15);
treeSet.add(2);
treeSet.add(84);
treeSet.add(8);
treeSet.add(10);
treeSet.add(8);
System.out.println(treeSet);
}
}
HashSet
底层原理: HashSet集合底层采用哈希表存储的数据,哈希表是一种对于增删改查数据性能较好的结构。JDK8之前,底层使用数组+链表组成;JDK8底层使用数组+链表+红黑树组成。
哈希值:JDK根据对象的地址,按照某种规则计算出来的int类型的数值。可以通过Object类提供的API获取对象的hash值。
public int hashCode():返回对象的哈希值
同一个对象多次调用hashCode方法返回的哈希值是相同的;默认情况下不同对象的hash值不同
HashSet底层实现
- 创建一个默认长度为16的数组,默认加载0.75的数组,数组名为table
- 根据元素的hash值和数组的长度求余计算出对应的存入位置(哈希算法)
- 如果存入的位置的元素是null则直接存入;否则会调用equals方法,如果值相同不存入,如果值不同则存入。
- 当数组存满16*0.75 = 12时就自动扩容,每次扩容原先的两倍
JDK8之前,新元素会占老元素位置,指向老元素
JDK8,新元素挂在老元素下面,当挂在元素下面的数据过多时,查询性能降低。从JDK8开始,当链表长度大于8时,自动转换成红黑树。
去重复底层实现原理
HashSet集合存入数据时,会先根据元素哈希值和数组长度进行求余计算存入位置,如果存入位置无元素,则直接存入;否则会调用equals去判断元素是否相同,如果不相同则存入。
结论:如果希望Set集合认为两个内容一样的对象是重复的,必须重写对象的hashCode()和equals()方法
案例: 创建一个存储学生对象的集合,存储多个学生对象,当学生对象的成员变量相同,就认为是同一个对象
package com.spark.setstudy;
import java.util.Objects;
/**
* Student class
* description: Set集合对象去重复
*
* @author Administrator
* @date 2023/4/5
*/
public class Student {
private String name;
private int age;
private String sex;
public Student() {
}
public Student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
// 重写hashCode和equals方法
// 重写equals,当对象内容一样时表示对象相同
@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 && Objects.equals(name, student.name) && Objects.equals(sex, student.sex);
}
// 重写hashCode
// 获取对象的hash值
@Override
public int hashCode() {
return Objects.hash(name, age, sex);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", 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 String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
package com.spark.setstudy;
import java.util.HashSet;
import java.util.Set;
/**
* Test class
* description: Set接口的实现类特点
*
* @author Administrator
* @date 2023/3/15
*/
public class Test {
public static void main(String[] args) {
Set<Student> students = new HashSet<Student>();
Student stu1 = new Student("张三",20,"男");
Student stu2 = new Student("李四",22,"男");
Student stu3 = new Student("王五",24,"男");
Student stu4 = new Student("王五",24,"男");
students.add(stu1);
students.add(stu2);
students.add(stu3);
students.add(stu4);
System.out.println(students);
}
}
LinkedHashSet
特点:有序、无重复、无索引
有序指的是保证存储和取出元素的顺序一致
原理:底层结构依然是哈希表,只是每个元素之间多了一个双链表的机制记录存储的顺序
TreeSet
特点:无重复,无索引,可排序
可排序:按照元素大小,默认是升序排列
原理:TreeSet底层是基于红黑树的数据结构实现排序的,增删改查性能好
TreeSet集合是一定要排序的,可以将元素按照指定的规则进行排序。
TreeSet集合默认的规则
- 数值类型:Integer、Double,默认是按照大小升序排列
- 字符串类型:默认按照首字符的编号升序排列
- 自定义类型:如对象,TreeSet无法直接排序,需要制定排序规则
TreeSet集合存储对象的时候有两种方式可以设计自定义比较规则
- 自定义类实现Comparable接口重写里面的compareTo方法制定比较规则
- TreeSet集合有参构造器,可以设置Comparator接口对应的比较器对象,来制定比较规则
package com.spark.treeset;
import java.util.Objects;
/**
* Apple class
* description: TreeSet排序自定义类型
*
* @author Administrator
* @date 2023/4/5
*/
public class Apple {
private String name;
private double price;
public Apple() {
}
public Apple(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Apple apple = (Apple) o;
return Double.compare(apple.price, price) == 0 && Objects.equals(name, apple.name);
}
@Override
public int hashCode() {
return Objects.hash(name, price);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Apple{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
package com.spark.treeset;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
/**
* Test class
* description: TODO
*
* @author Administrator
* @date 2023/4/5
*/
public class Test {
public static void main(String[] args) {
// 自定义比较规则 按照价格降序排列
Comparator<Apple> comparator = Comparator.comparing(Apple::getPrice).reversed();
Set<Apple> apples = new TreeSet<>(comparator);
apples.add(new Apple("红富士",9.9));
apples.add(new Apple("青苹果",19.9));
apples.add(new Apple("黄苹果",9.9));
System.out.println(apples);
// 使用构造器自定义排序规则 升序排列 当价格相同时会去除重复数据
// lambda简化
Set<Apple> apples2 = new TreeSet<>((o1,o2)->Double.compare(o1.getPrice(), o2.getPrice()));
apples2.add(new Apple("红富士",9.9));
apples2.add(new Apple("青苹果",19.9));
apples2.add(new Apple("黄苹果",9.9));
System.out.println(apples2);
}
}
可变参数列表
可变参数列表在形参中可以接收多个数据
可变参数的格式:数据类型... 参数名称
作用:传输参数非常灵活、方便。可以不传输参数,可以传输1个或多个,也可以传输一个数组
package com.spark.params;
import java.util.Arrays;
/**
* Test class
* description: TODO
*
* @author Administrator
* @date 2023/4/5
*/
public class Test {
public static void main(String[] args) {
// 不传值
sum();
// 传1个值
sum(10);
// 传多个值
sum(20,31,5);
// 传一个数组
sum(new int[]{1,2,3,4,5});
}
public static void sum(int... numbers){
System.out.println("元素个数:"+numbers.length);
System.out.println("元素内容:"+ Arrays.toString(numbers));
}
}
可变参数列表在形参中只能有一个;可变参数列表必须放在形参的最后一位
集合工具类Collections
Collections是操作集合的工具类,不属于集合,位于java.utils.Collections
常用API
- addAll(Collection<? super T> collection, T... elements) 给集合对象批量添加元素
- shuffle(List<?> list)打乱list集合中的元素顺序
- sort(List<?> list)将list集合中的元素排序
- sort(List<?> list, Comparator<T> comparator)使用比较器自定义排序规则
package com.spark.collections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Test class
* description: TODO
*
* @author Administrator
* @date 2023/4/5
*/
public class Test {
public static void main(String[] args) {
// 添加元素
List<Integer> numbers = new ArrayList<>();
Collections.addAll(numbers,1,2,3,4,6);
System.out.println(numbers);
// 打乱列表中的元素,只能打乱List集合
Collections.shuffle(numbers);
System.out.println(numbers);
// 排序
Collections.sort(numbers);
System.out.println(numbers);
// 排序按照排序规则降序
Collections.sort(numbers, (o1,o2)-> Integer.compare(o2,o1));
System.out.println(numbers);
}
}
Map体系
Map集合是一种双列集合,每个元素包含两个数据。Map集合也称为键值对集合。
Map集合的每个元素的格式:key=value(键值对元素)
特点
- Map集合的特点都是由键决定的
- Map集合的键无序、无重复、无索引
- Map集合后面添加的重复的键对应的值会覆盖前面重复键的值
- Map集合的键值对都可以是null
常用API
-
put(K key, V value) 添加元素
-
remove(Object key) 根据键删除元素
-
clear() 移除所有的键值对元素
-
containsKey(Object key) 判断集合是否包含指定的键
-
containsValue(Object value) 判断集合是否包含指定的值
-
isEmpty() 判断集合是否为空
-
size() 集合的长度,也就是集合中键值对的个数
-
keySet() 获取全部键的集合
-
values() 获取全部值的集合
package com.spark.mapstudy;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Test class
* description: Map常用API
*
* @author Administrator
* @date 2023/4/5
*/
public class Test {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
// 添加元素
map.put("java","Java基础");
map.put("html","Java前端");
map.put("python","Python入门");
// 相同的key后面的值会覆盖前面重复键对应的值
map.put("java","Java从入门到精通");
System.out.println(map);
// 删除元素
map.remove("html");
System.out.println(map);
// 判断是否包含指定的键
System.out.println(map.containsKey("java"));
System.out.println(map.containsKey("html"));
// 判断是否包含指定的值
System.out.println(map.containsValue("Java从入门到精通"));
System.out.println(map.containsValue("数据结构与算法"));
// 获取集合的长度
System.out.println(map.size());
// 获取键集合
Set<String> keys = map.keySet();
keys.forEach(key-> System.out.println(key));
// 获取值集合
Collection<String> values = map.values();
values.forEach(value-> System.out.println(value));
// 清空map集合
map.clear();
System.out.println(map);
// 判断集合是否为空
System.out.println(map.isEmpty());
// 合并map集合
Map<String,String> map2 = new HashMap<>();
map2.put("css","css3");
map2.put("jquery","js封装");
map.putAll(map2);
System.out.println(map);
System.out.println(map2);
}
}
遍历
方式一:键找值
package com.spark.mapstudy;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* ForEachTest class
* description: 键找值
*
* @author Administrator
* @date 2023/4/5
*/
public class ForEachTest {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("java","Java从入门到精通");
map.put("html","html5入门");
map.put("css","css3设计");
System.out.println(map);
// 获取所有键的集合
Set<String> keys = map.keySet();
// 根据键获取值
for (String key : keys) {
System.out.println(map.get(key));
}
}
}
方式二:键值对
package com.spark.mapstudy;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* ForEachTest2 class
* description: 键值对遍历
*
* @author Administrator
* @date 2023/4/5
*/
public class ForEachTest2 {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("java","Java从入门到精通");
map.put("html","html5入门");
map.put("css","css3设计");
System.out.println(map);
// 将Map集合转换为Set集合
Set<Map.Entry<String, String>> entries = map.entrySet();
// 遍历Set集合中的实体类型
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"=====>"+value);
}
}
}
方式三:lambda表达式
package com.spark.mapstudy;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
/**
* ForEachTest3 class
* description: lambda表达式
*
* @author Administrator
* @date 2023/4/5
*/
public class ForEachTest3 {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("java","Java从入门到精通");
map.put("html","html5入门");
map.put("css","css3设计");
System.out.println(map);
// forEach遍历
map.forEach(new BiConsumer<String, String>() {
@Override
public void accept(String k, String v) {
System.out.println(k+"------>"+v);
}
});
// lambda表达式简化代码
map.forEach((k,v)->{
System.out.println(k+"----->"+v);
});
}
}
实现类
HashMap
HashMap是Map的一个实现类。HashMap跟HashSet底层原理相同,都是Hash表结构,只是HashMap的每个元素包含两个对象
Set系列集合的底层就是由Map实现的,只是Set集合里面的元素只要键数据,不要值数据
public HashSet(){
map = new HashMap<>();
}
特点
- 由键决定:无序、无重复、无索引。HashMap底层是哈希表结构
- 依赖hashCode方法和equals方法保证键唯一
- 如果键要存储的是自定义对象,需要重写hashCode和equals方法
- 基于哈希表,增删改查的性能都较好
LinkedHashMap
特点:有序、无重复、无索引
底层也是哈希表结构,存储的时候每个键值对元素额外多了一个双链表机制记录存储的顺序
LinkedHashSet集合底层创建的是LinkedHashMap集合。创建LinkedHashSet时,构造器会通过super关键字调用HashSet其中的一个有参构造器,该构造器会实例化一个LinkedHashMap集合
TreeMap
特点:不重复、无索引、可排序
可排序:按照键数据的大小默认升序(由小到大)排序。只能对键排序
TreeMap是一定要排序的,可以默认排序,也可以将键按照指定的规则进行排序。用法可以参考TreeSet