32. 【Java教程】集合

在前面的小节中,我们学习了数组,本小节学习的集合同样用于存放一组数据,我们将学习什么是集合集合的应用场景 ,在应用场景部分我们将对比 Java 数组与集合的区别,还将系统介绍 Java 集合的架构,也将结合实例来讲解集合的实际应用。

1. 什么是集合

在计算机科学中,集合是一组可变数量的数据项(也可能为 0 个)的组合,这些数据可能共享某些特征,需要以某种操作方式一起进行操作。

Java 中集合主要分为java.util.Collectionjava.util.Map两大接口。

下图描绘了 Java 集合的框架:

Tips: 图表最下方的ArrayListLinkedListHashSet以及HashMap都是常用实现类,本小节将介绍具体使用。

1.1 Collection

java.util.Collection接口的实现可用于存储 Java 对象。例如,学校所有学生可以视为一个Collection

Collection又可以分为三个子接口,分别是:

  1. List:序列,必须按照顺序保存元素,因此它是有序的,允许重复;
  2. Queue:队列,按照排队规则来确定对象产生的顺序,有序,允许重复;
  3. Set:集,不能重复。

1.2 Map

java.util.Map接口的实现可用于表示“键”(key)和“值”(value)对象之间的映射。一个映射表示一组“键”对象,其中每一个“键”对象都映射到一个“值”对象。因此可以通过键来查找值。例如,每一个学生都有他自己的账户积分,这个关联关系可以用Map来表示。

2. 集合的应用场景

2.1 数组与集合

在介绍集合的应用场景之前,我们先来看看数组和集合的对比。

我们知道数组和集合都用于存放一组数据,但数组的容量是固定大小的,而集合的容量是动态可变的;对于可存放的数据类型,数组既可以存放基本数据类型又可以存放引用数据类型,而集合只能存放引用数据类型,基本数据类型需要转换为对应的包装类才能存放到集合当中。

2.2 集合应用场景

  • 无法预测存储数据的数量:由于数组容量是固定大小,因此使用集合存储动态数量的数据更为合适;
  • 同时存储具有一对一关系的数据:例如存储学生的积分,为了方便检索对应学生的积分,可使用Map将学生的uid和对应的积分进行一对一关联;
  • 数据去重:使用数组实现需要遍历,效率低,而Set集合本身就具有不能重复的特性;
  • 需要数据的增删:使用数组实现增删操作需要遍历、移动数组中元素,如果操作频繁会导致效率降低。

3. List 集合

3.1 概念和特性

List 是元素有序并且可以重复的集合,称之为序列。序列可以精确地控制每个元素的插入位置或删除某个位置的元素。通过前面的学习,我们知道ListCollection的一个子接口,它有两个主要实现类,分别为ArrayList(动态数组)和LinkedList(链表)。

3.2 ArrayList 实现类

ArrayList 可以理解为动态数组,它的容量可以动态增长。当添加元素时,如果发现容量已满,会自动扩容为原始大小的 1.5 倍。

3.2.1 构造方法
  • ArrayList():构造一个初始容量为 10 的空列表;
  • ArrayList(int initialCapacity):构造一个指定容量的空列表;
  • ArrayList(Collection<? extends E> c):构造一个包含指定集合元素的列表,其顺序由集合的迭代器返回。

在代码中,我们可以这样实例化ArrayList对象:

// 无参构造实例化,初始容量为10
List arrayList1 = new ArrayList();
// 实例化一个初始容量为20的空列表
List arrayList2 = new ArrayList(20);
// 实例化一个集合元素为 arrayList2 的列表(由于 arrayList2 为空列表,因此其实例化的对象也为空列表)
List arrayList3 = new ArrayList(arrayList2);
3.2.2 常用成员方法
  • void add(E e):将指定的元素追加到此列表的末尾;

  • void add(int index, E element):将指定的元素插入此列表中的指定位置;

  • E remove(int index):删除此列表中指定位置的元素;

  • boolean remove(Object o):如果存在指定元素,则从该列表中删除第一次出现的该元素;

  • void clear():从此列表中删除所有元素;

  • E set(int index, E element):用指定的元素替换此列表中指定位置的元素;

  • E get(int index):返回此列表中指定位置的元素;

  • boolean contains(Object o):如果此列表包含指定的元素,则返回 true,否则返回 false;

  • int size():返回该列表中元素的数量;

  • Object[] toArray():以正确的顺序(从第一个元素到最后一个元素)返回一个包含此列表中所有元素的数组。

更多成员方法请翻阅官方文档,下面我们将结合实例来介绍以上成员方法的使用。

3.3 实例

3.3.1 新增元素

请查看如下实例:

import java.util.ArrayList;
import java.util.List;public class ArrayListDemo1 {public static void main(String[] args) {// 实例化一个空列表List arrayList = new ArrayList();for (int i = 0; i < 5; i ++) {// 将元素 i 追加到列表的末尾arrayList.add(i);// 打印列表内容System.out.println(arrayList);}}
}

运行结果:

[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]

代码中,首先实例化了一个ArrayList对象,然后使用 for 循环语句循环 5 次,每次都向arrayList对象中追加变量i,并打印列表内容,运行结果清晰的展示了每次新增元素的过程。

Tips:由于ArrayList的父类AbstractCollection重写了toString()方法,因此直接打印列表,可以直观地展示出列表中的元素。

3.3.2 泛型初识

Tips:泛型(Genericity)**将在下一小节详细介绍,此处我们只简要介绍一下泛型以及其使用方法。如果你比较了解泛型,可直接跳过此知识点。

如果你使用IDEA编写如上代码,将会有下图所示的 3 处黄色警告:

既然IDE有了警告,我们就尝试来解决一下,将鼠标光标放置到警告处,会提示“Unchecked call to ‘add(E)’ as a member of raw type ‘java.util.List’ ”,这是IDE泛型检查,可点击Try to generify 'ArrayListDemo1.java'按钮:

此时会出现一个Generify的弹窗,直接点击Refactor按钮:

代码变成了下图所示的样子,那 3 处警告被成功消除了:

我们观察到代码第 8 行的List类型后面多了一对尖括号“<>”,<>里面是 Java 的包装类型Integer,在ArrayList类型后面也多了一对尖括号,这里的<>中承载的就是 Java 的泛型的类型参数,它表示arrayList对象用于存放Integer类型的数据。这样的目的和好处这里不详细展开讨论,本小节我们只需知道这样做就可以消除IDEA的警告即可。

由于前面List已经指定了泛型的参数类型为Integer,后面的ArrayList就不需要再重复指定了。当然你也可以这样写(但是没必要):

List<Integer> arrayList = new ArrayList<Integer>();

同理,如果你想向arrayList存放String类型的元素,只需将<Integer>改为<String>,我们再来看一个实例:

import java.util.ArrayList;
import java.util.List;public class ArrayListDemo2 {public static void main(String[] args) {// 实例化一个空列表List<String> arrayList = new ArrayList<>();// 将字符串元素 Hello 追加到此列表的末尾arrayList.add("Hello");// 将字符串元素 World 追加到此列表的末尾arrayList.add("World");// 打印列表System.out.println(arrayList);// 将字符串元素 Java 插入到此列表中的索引为 1 的位置arrayList.add(1, "Java");// 打印列表System.out.println(arrayList);}
}

运行结果:

[Hello, World]
[Hello, Java, World]

代码中,首先实例化了一个ArrayList的对象,调用了两次add(E e)方法,依次向列表尾部插入了HelloWorld元素,列表中元素为[Hello, World],此时调用add(int index, E element)方法,将字符串元素 Java 插入到此列表中的索引为 1 的位置,因此列表中的元素为[Hello, Java, World]

3.3.3 删除元素

请查看如下实例:

import java.util.ArrayList;
import java.util.List;public class ArrayListDemo3 {public static void main(String[] args) {// 实例化一个空列表List<String> arrayList = new ArrayList<>();// 将字符串元素 Hello 追加到此列表的末尾arrayList.add("Hello");// 将字符串元素 World 追加到此列表的末尾arrayList.add("World");// 将字符串元素 Hello 追加到此列表的末尾arrayList.add("Hello");// 将字符串元素 Java 追加到此列表的末尾arrayList.add("Java");// 打印列表System.out.println(arrayList);// 删除此列表中索引位置为 3 的元素arrayList.remove(3);// 打印列表System.out.println(arrayList);// 删除此列表中第一次出现的 Hello 元素arrayList.remove("Hello");System.out.println(arrayList);}
}

运行结果:

[Hello, World, Hello, Java]
[Hello, World, Hello]
[World, Hello]

代码中,我们首先添加了 4 个字符串元素,列表内容为[Hello, World, Hello, Java],然后调用remove(int index)方法删除了索引位置为 3 的元素(即Java),此时列表内容为[Hello, World, Hello] ,再次调用remove(Object o)方法,删除了列表中第一次出现的Hello元素,此时列表内容为[World, Hello]

3.3.4 修改元素

可使用set()方法修改列表中元素,实例如下:

import java.util.ArrayList;
import java.util.List;public class ArrayListDemo4 {public static void main(String[] args) {// 实例化一个空列表List<String> arrayList = new ArrayList<>();arrayList.add("Hello");// 将字符串元素 World 追加到此列表的末尾arrayList.add("World");// 打印列表System.out.println(arrayList);// 用字符串元素 Hello 替换此列表中索引位置为 1 的元素arrayList.set(1, "Java");System.out.println(arrayList);}
}

运行结果:

[Hello, World]
[Hello, Java]
3.3.5 查询元素

可使用get()方法来获取列表中元素,实例如下:

import java.util.ArrayList;
import java.util.List;public class ArrayListDemo5 {public static void main(String[] args) {// 实例化一个空列表List<String> arrayList = new ArrayList<String>();arrayList.add("Hello");arrayList.add("Immoc");for (int i = 0; i < arrayList.size(); i ++) {System.out.println("索引位置" + i + "的元素为"  + arrayList.get(i));}}
}

运行结果:

索引位置0的元素为Hello
索引位置1的元素为Immoc

我们在使用for循环遍历列表的时候,让限定条件为i < arrayList.size();size()方法可获取该列表中元素的数量。

3.2.7 自定义类的常用操作

请查看如下实例:

import java.util.ArrayList;
import java.util.List;public class ArrayListDemo6 {static class MybjStudent {private String nickname;private String position;public MybjStudent() {}public MybjStudent(String nickname, String position) {this.setNickname(nickname);this.setPosition(position);}public String getNickname() {return nickname;}public void setNickname(String nickname) {this.nickname = nickname;}public String getPosition() {return position;}public void setPosition(String position) {this.position = position;}@Overridepublic String toString() {return "MybjStudent{" +"nickname='" + nickname + '\'' +", position='" + position + '\'' +'}';}}public static void main(String[] args) {// 实例化一个空列表List<MybjStudent> arrayList = new ArrayList<>();// 实例化3个学生对象MybjStudent mybjStudent1 = new MybjStudent("Colorful", "服务端工程师");MybjStudent mybjStudent2 = new MybjStudent("Lillian", "客户端工程师");MybjStudent mybjStudent3 = new MybjStudent("小张", "架构师");// 新增元素arrayList.add(mybjStudent1);arrayList.add(mybjStudent2);arrayList.add(mybjStudent3);System.out.println(arrayList);// 删除元素arrayList.remove(mybjStudent2);System.out.println("删除 mybjStudent2 后:arrayList 内容为:" + arrayList);arrayList.remove(1);System.out.println("删除列表中索引位置为 1 的元素后,arrayList 内容为:" + arrayList);// 实例化一个新的学生对象MybjStudent mybjStudent4 = new MybjStudent("小李", "UI设计师");// 修改元素arrayList.set(0, mybjStudent4);System.out.println("修改后:arrayList 内容为" + mybjStudent4);// 查询元素,将 get() 方法得到的 Object 类型强制转换为 MybjStudent 类型MybjStudent student = arrayList.get(0);System.out.println("索引位置 0 的学生的昵称为:" + student.getNickname());System.out.println("索引位置 0 的学生的职位为:" + student.getPosition());}
}

运行结果:

[MybjStudent{nickname='Colorful', position='服务端工程师'}, MybjStudent{nickname='Lillian', position='客户端工程师'}, MybjStudent{nickname='小张', position='架构师'}]
删除 mybjStudent2 后:arrayList 内容为:[MybjStudent{nickname='Colorful', position='服务端工程师'}, MybjStudent{nickname='小张', position='架构师'}]
删除列表中索引位置为 1 的元素后,arrayList 内容为:[MybjStudent{nickname='Colorful', position='服务端工程师'}]
修改后:arrayList 内容为MybjStudent{nickname='小李', position='UI设计师'}
索引位置 0 的学生的昵称为:小李
索引位置 0 的学生的职位为:UI设计师

为了方便演示,我们定义了一个静态内部类MybjStudent,它有两个属性nicknameposition,定义了属性的gettersetter,并重写了toString()方法。在main()方法中,我们实现了自定义类在ArrayList中的增删改查。

3.4 LinkedList 实现类

LinkedList 是一个以双向链表实现的List。和ArrayList一样,也按照索引位置排序,但它的元素是双向连接的,因此顺序访问的效率非常高,而随机访问的效率比较低。

3.4.1 构造方法
  • LinkedList():构造一个空列表;
  • LinkedList(Collection<? extends E> c):构造一个包含指定集合元素的列表,其顺序由集合的迭代器返回。
3.4.2 常用成员方法
  • void add(E e):将指定的元素追加到此列表的末尾;
  • void add(int index, E element):将指定的元素插入此列表中的指定位置;
  • void addFirst(E e):将指定的元素插入此列表的开头;
  • vod addLast(E e):将指定的元素添加到此列表的结尾;
  • E remove(int index):删除此列表中指定位置的元素;
  • boolean remove(Object o):如果存在指定元素,则从该列表中删除第一次出现的该元素;
  • void clear():从此列表中删除所有元素;
  • E set(int index, E element):用指定的元素替换此列表中指定位置的元素;
  • E get(int index):返回此列表中指定位置的元素;
  • E getFirst():返回此列表的第一个元素;
  • E getLast():返回此列表的最后一个元素;
  • boolean contains(Object o):如果此列表包含指定的元素,则返回 true,否则返回 false;
  • int size():返回该列表中元素的数量;
  • Object[] toArray():以正确的顺序(从第一个元素到最后一个元素)返回一个包含此列表中所有元素的数组。

更多成员方法请翻阅官方文档,对于成员方法的使用,与ArrayList大同小异,这里不再赘述。

4. Set 集合

4.1 概念和特性

Set是元素无序并且不可以重复的集合,我们称之为集。SetCollection的一个子接口,它的主要实现类有:HashSetTreeSetLinkedHashSetEnumSet等,下面我们将详细介绍最常用的HashSet实现类。

4.2 HashSet 实现类

HashSet类依赖于哈希表(实际上是HashMap实例,下面将会介绍)。HashSet中的元素是无序的、散列的。

4.2.1 构造方法
  • HashSet():构造一个新的空集;默认的初始容量为 16(最常用),负载系数为 0.75;
  • HashSet(int initialCapacity):构造一个新的空集; 具有指定的初始容量,负载系数为 0.75;
  • HashSet(int initialCapacity, float loadFactor):构造一个新的空集; 支持的 HashMap 实例具有指定的初始容量和指定的负载系数;
  • HashSet(Collection<? extends E> c):构造一个新集合,其中包含指定集合中的元素。
4.2.2 常用成员方法

HashSet的常用成员方法如下:

  • boolean add(E e):如果指定的元素尚不存在,则将其添加到该集合中;
  • boolean contains(Object o):如果此集合包含指定的元素,则返回 true,否则返回 false;
  • boolean isEmpty():如果此集合不包含任何元素,则返回 true,否则返回 false;
  • Iterator<E> iterator():返回此集合中元素的迭代器;
  • boolean remove(Object o):从该集合中删除指定的元素(如果存在);
  • int size():返回此集合中的元素数量。

更多成员方法请翻阅官方文档,下面我们将结合实例来介绍以上成员方法的使用。

4.3 实例

4.3.1 新增元素

可使用add()方法向集中添加元素,实例如下:

import java.util.HashSet;
import java.util.Set;public class HashSetDemo1 {public static void main(String[] args) {// 实例化一个新的空集Set<String> hashSet = new HashSet<String>();// 向 hashSet 集中依次添加元素:Python、Java、PHP、TypeScript、PythonhashSet.add("Python");hashSet.add("Java");hashSet.add("PHP");hashSet.add("TypeScript");hashSet.add("Python");// 打印 hashSet 的内容System.out.println("hashSet中的内容为:" + hashSet);}
}

运行结果:

hashSet中的内容为:[TypeScript, Java, PHP, Python]

在实例中,我们先后向hashSet中添加了两次Python元素,由于集的元素不可重复特性,因此集中只允许出现一个Python元素。我们还观察到,打印结果的元素顺序和我们添加的顺序是不同的,这验证了集的无序特性

Tips: 由于HashSet的父类AbstractCollection重写了toString()方法,因此直接打印集,可以直观地展示出集中的元素。

4.3.2 删除元素

可使用remove()方法删除集中元素,实例如下:

实例演示

import java.util.HashSet;
import java.util.Set;public class HashSetDemo2 {public static void main(String[] args) {// 实例化一个新的空集Set<String> hashSet = new HashSet<>();// 向 hashSet 集中依次添加元素:Python、JavahashSet.add("Python");hashSet.add("Java");// 打印 hashSet 的内容System.out.println(hashSet);// 删除 hashSet 中的 Python 元素hashSet.remove("Python");// 打印 hashSet 的内容System.out.println("删除 Python 元素后,hashSet中的内容为:" + hashSet);}
}

运行结果:

[Java, Python]
删除 Python 元素后,hashSet中的内容为:[Java]
4.3.3 查询元素

我们知道了ArrayList 通过 get方法来查询元素,但HashSet没有提供类似的get方法来查询元素。

这里我们介绍一个迭代器(Iterator)接口,所有的Collection都实现了Iterator接口,它可以以统一的方式对各种集合元素进行遍历。我们来看下Iterator接口的常用方法:

  • hasNaxt() 方法检测集合中是否还有下一个元素;

  • next()方法返回集合中的下一个元素;

  • iterator():返回此集合中元素的迭代器。

实例如下:

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;public class HashSetDemo3 {public static void main(String[] args) {// 实例化一个新的空集Set<String> hashSet = new HashSet<String>();// 向 hashSet 集中依次添加元素:Python、Java、PHPhashSet.add("Python");hashSet.add("Java");hashSet.add("PHP");// 打印 hashSet 的内容System.out.println(hashSet);// 获取 hashSet 中元素的迭代器Iterator<String> iterator = hashSet.iterator();System.out.println("迭代器的遍历结果为:");while (iterator.hasNext()) {System.out.println(iterator.next());}}
}

运行结果:

[Java, PHP, Python]
迭代器的遍历结果为:
Java
PHP
Python
4.3.4 自定义类的常用操作

请查看如下实例:

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;public class HashSetDemo4 {/*** 静态内部类:学生*/static class MybjStudent {private String nickname;private String position;public MybjStudent() {}public MybjStudent(String nickname, String position) {this.setNickname(nickname);this.setPosition(position);}public String getNickname() {return nickname;}public void setNickname(String nickname) {this.nickname = nickname;}public String getPosition() {return position;}public void setPosition(String position) {this.position = position;}@Overridepublic String toString() {return "MybjStudent{" +"nickname='" + nickname + '\'' +", position='" + position + '\'' +'}';}}public static void main(String[] args) {Set<MybjStudent> hashSet = new HashSet<>();// 实例化3个学生对象MybjStudent mybjStudent1 = new MybjStudent("Colorful", "服务端工程师");MybjStudent mybjStudent2 = new MybjStudent("Lillian", "客户端工程师");MybjStudent mybjStudent3 = new MybjStudent("小张", "架构师");// 新增元素hashSet.add(mybjStudent1);hashSet.add(mybjStudent2);hashSet.add(mybjStudent3);// 使用Iterator遍历hashSetIterator<MybjStudent> iterator = hashSet.iterator();System.out.println("迭代器的遍历结果为:");while (iterator.hasNext()) {System.out.println(iterator.next());}// 查找并删除if (hashSet.contains(mybjStudent1)) {hashSet.remove(mybjStudent1);}System.out.println("删除nickname为Colorful的对象后,集合元素为:");System.out.println(hashSet);}
}

运行结果:

迭代器的遍历结果为:
MybjStudent{nickname='Lillian', position='客户端工程师'}
MybjStudent{nickname='Colorful', position='服务端工程师'}
MybjStudent{nickname='小张', position='架构师'}
删除nickname为Colorful的对象后,集合元素为:
[MybjStudent{nickname='Lillian', position='客户端工程师'}, MybjStudent{nickname='Colorful', position='服务端工程师'}, MybjStudent{nickname='小张', position='架构师'}]

为了方便演示,我们定义了一个静态内部类MybjStudent,它有两个属性nicknameposition,定义了属性的gettersetter,并重写了toString()方法。在main()方法中,我们实现了自定义类在HashSet中的增删改查,使用迭代器可以遍历元素。

5. Map 集合

5.1 概念和特性

我们已经知道Map是以键值对(key-value)的形式存储的对象之间的映射,key-value是以java.util.Map.Entry类型的对象实例存在。

可以使用键来查找值,一个映射中不能包含重复的键,但值是可以重复的。每个键最多只能映射到一个值。

5.2 HashMap 实现类

HashMapjava.util.Map接口最常用的一个实现类,前面所学的HashSet底层就是通过HashMap来实现的,HashMap允许使用null键和null值。

5.2.1 构造方法
  • HashMap():构造一个新的空映射;默认的初始容量为 16(最常用),负载系数为 0.75;

  • HashMap(int initialCapacity):构造一个新的空映射; 具有指定的初始容量,负载系数为 0.75;

  • HashMap(int initialCapacity, float loadFactor):构造一个新的空映射; 支持的 HashMap 实例具有指定的初始容量和指定的负载系数;

  • HashSet(Map<? extends K, ? extends V> m):构造一个新映射,其中包含指定映射相同。

5.2.2 常用成员方法
  • void clear():从该映射中删除所有映射;
  • Set<Map, Entry<K, V>> entrySet:返回此映射中包含的映射的集合;
  • V get(Object key):返回指定键映射到的值,如果该映射不包含键的映射,则返回 null;
  • Set<K> keySet:返回此映射中包含的的结合;
  • V put(K key, V value):将指定值与此映射中指定键关联;
  • V remove(Object key):如果存在,则从此映射中删除指定键的映射。
  • Collection<V> values:返回此映射中包含的集合。

5.3 实例

下面我们使用 HashMap 来实现一个英汉字典的例子。

实例演示

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;public class HashMapDemo1 {public static void main(String[] args) {Map<String, String> map = new HashMap<>();// 添加数据map.put("English", "英语");map.put("Chinese", "汉语");map.put("Java", "咖啡");// 打印 mapSystem.out.println(map);// 删除 key 为 Java 的数据map.remove("Chinese");System.out.println("删除键为Chinese的映射后,map内容为:");// 打印 mapSystem.out.println(map);// 修改元素:map.put("Java", "一种编程语言");System.out.println("修改键为Java的值后,Java=" + map.get("Java"));// 遍历mapSystem.out.println("通过遍历entrySet方法得到 key-value 映射:");Set<Entry<String, String>> entries = map.entrySet();for (Entry<String, String> entry: entries) {System.out.println(entry.getKey() + " - " + entry.getValue());}// 查找集合中键为 English 对应的值Set<String> keySet = map.keySet();for (String key: keySet) {if (key.equals("English")) {System.out.println("English 键对应的值为:" + map.get(key));break;}}}
}

运行结果:

{English=英语, Java=咖啡, Chinese=汉语}
删除键为Chinese的映射后,map内容为:
{English=英语, Java=咖啡}
修改键为Java的值后,Java=一种编程语言
通过遍历entrySet方法得到 key-value 映射:
English - 英语
Java - 一种编程语言
English 键对应的值为:英语

实例中,Map 的 key 是字符串类型,value 也是字符串类型。值得注意的是,我们在创建HashMap的时候,在Map类型的后面有一个<String, String>,分别表示映射中将要存放的 key 和 value 的类型都为 String 类型。在遍历映射的时候,我们调用了entrySet方法,它返回了此映射中包含的映射的集合。通过键查找值,我们可以调用keySet方法来获取映射中的键的集合,并且遍历这个集合即可找到对应键,通过键就可以获取值了。

6. 小结

本小节我们学习了 Java 的集合,它们定义在java.util包中,Java 中的集合主要有CollectionMap两大接口。List集合是元素有序并且可以重复的集合;Set集合是元素无序并且不可以重复的集合;Map是以键值对(key-value)的形式存储的对象之间的映射,它们都支持泛型。我们分别介绍了 3 个接口常用的实现类的用法。同学们要多多进行编码练习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/337082.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【课程总结】Day4:信息论和决策树算法

前言 本章内容主要是学习机器学习中的一个重要模型&#xff1a;决策树&#xff0c;围绕决策树的应用&#xff0c;我们展开了解到&#xff1a;熵的定义、熵的计算、决策树的构建过程(基于快速降熵)、基尼系数等&#xff0c;从而使得我们对决策树有了直观认识。 熵的介绍 因为…

用HAL库改写江科大的stm32入门-6-3 PWM驱动LED呼吸灯

接线图&#xff1a; 2 :实验目的&#xff1a; 利用pwm实现呼吸灯。 关键PWM定时器设置&#xff1a; 代码部分&#xff1a; int main(void) {/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*…

10.Halcon3D点云和MESH的相互转换

1.实现效果 这个案例主要是想告诉我们,如何在点云数据(全是点)和MESH(网格数据)中转换,理论上说可以点云数据可以看作的离散的,而MESH网格数据可以看作是连续的。 上图展示了三个(其实是四个)空间中的3d对象,左边第一个是一个立方体,经过降采样之后的点云,中间的是…

匿名函数(lambda)

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 匿名函数是指没有名字的函数&#xff0c;应用在需要一个函数&#xff0c;但是又不想费神去命名这个函数的场合。通常情况下&#xff0c;这样的函数只…

LabVIEW中进行步进电机的位置控制

在LabVIEW中进行步进电机的位置控制&#xff0c;通常涉及以下几个关键步骤&#xff1a;设置硬件、配置通信、编写控制算法和实施反馈控制。以下是一个详细的介绍。 硬件设置 步进电机&#xff1a;选择合适的步进电机&#xff0c;根据负载和应用需求选择适当的步数和转矩。 驱…

TensorFlow Playground神经网络演示工具使用方法详解

在现代机器学习领域,神经网络无疑是一个重要的研究方向。然而,对于许多初学者来说,神经网络的概念和实际操作可能显得相当复杂。幸运的是,TensorFlow Playground 提供了一个交互式的在线工具,使得我们可以直观地理解和实验神经网络的基本原理。在这篇博客中,我们将详细介…

IMU状态预积分代码实现 —— IMU状态预积分类

IMU状态预积分代码实现 —— IMU状态预积分类 实现IMU状态预积分类 实现IMU状态预积分类 首先&#xff0c;实现预积分自身的结构。一个预积分类应该存储一下数据&#xff1a; 预积分的观测量 △ R ~ i j , △ v ~ i j , △ p ~ i j \bigtriangleup \tilde{R} _{ij},\bigtrian…

Superset二次开发之更新 SECRET_KEY

SECRET_KEY 的作用 加密和签名:SECRET_KEY用于对敏感数据(如会话、cookie、CSRF令牌)进行加密和签名,防止数据被篡改。安全性:确保应用的安全性,防止跨站请求伪造(CSRF)攻击和会话劫持等安全问题。如何生成 SECRET_KEY openssl rand -base64 42 配置 SECRET_KEY 在sup…

git使用流程与规范

原文网址&#xff1a;git代码提交流程与规范-CSDN博客 简介 本文git提交流程与规范是宝贵靠谱的经验&#xff0c;它能解决如下问题&#xff1a; 分支差距过大&#xff0c;导致合代码无数的冲突合完代码后发现代码丢失分支不清晰&#xff0c;无法追溯问题合代码耗时很长&…

使用Spring Boot自定义注解 + AOP实现基于IP的接口限流和黑白名单

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

数据在内存中的存储<C语言>

导言 在计算机中不同类型的数据在计算机内部存储形式各不相同&#xff0c;弄懂各种数据在计算机内部存储形式是有必要的&#xff0c;C语言的学习不能浮于表面&#xff0c;更要锻炼我们的“内功”&#xff0c;将来在写程序的时候遇见各种稀奇古怪的bug时&#xff0c;也便能迎刃而…

应用案例|精密制造中使用复合机器人得到显著提升

精密制造行业对设备的精度、稳定性和效率要求极高&#xff0c;而复合机器人凭借其多功能性、高度灵活性和精准控制能力&#xff0c;正逐渐成为该领域的新宠。以下是一个富唯智能复合机器人在精密制造中的应用案例。 案例背景 某知名汽车零部件制造企业&#xff0c;专注于生产…

u盘文件保密的方法有哪些?关于U盘的使用你要知道这些!

U盘作为便携式的存储设备&#xff0c;被广泛应用于日常工作和生活中。 然而&#xff0c;U盘的丢失或被盗可能导致敏感数据泄露&#xff0c;因此&#xff0c;掌握U盘文件保密的方法至关重要。 本文将介绍几种有效的U盘文件保密方法&#xff0c;并分享关于U盘使用的关键知识&…

Threejs(WebGL)绘制线段优化:Shader修改gl.LINES模式为gl.LINE_STRIP

目录 背景 思路 Threejs实现 记录每条线的点数 封装原始裁剪索引数据 封装合并几何体的缓冲数据&#xff1a;由裁剪索引组成的 IntArray 守住该有的线段&#xff01; 修改顶点着色器 修改片元着色器 完整代码 WebGL实现类似功能&#xff08;简易版&#xff0c;便于测…

cdo | 常用命令

整理一下平时经常会使用的cdo命令 如何来更改netcdf数据中的变量名呢&#xff1f; 假设我现在有一个sst月平均数据,希望将里面的变量名称sst修改为sst_new netcdf oisst_monthly { dimensions:lat 180 ;lon 360 ;time UNLIMITED ; // (476 currently)nbnds 2 ; variable…

音视频开发14 FFmpeg 视频 相关格式分析 -- H264 NALU格式分析

H264简介-也叫做 AVC H.264&#xff0c;在MPEG的标准⾥是MPEG-4的⼀个组成部分–MPEG-4 Part 10&#xff0c;⼜叫Advanced Video Codec&#xff0c;因此常常称为MPEG-4 AVC或直接叫AVC。 原始数据YUV,RGB为什么要压缩-知道就行 在⾳视频传输过程中&#xff0c;视频⽂件的传输…

Element快速入门

Vue组件库Element 1 Element介绍 vue是侧重于VM开发的&#xff0c;主要用于数据绑定到视图的&#xff0c;ElementUI就是一款侧重于V开发的前端框架&#xff0c;主要用于开发美观的页面的。 Element&#xff1a;是饿了么公司前端开发团队提供的一套基于 Vue 的网站组件库&…

使用pytorch搭建textCNN、BERT、transformer进行文本分类

首先展示数据处理后的类型&#xff1a; 第一列为文本&#xff0c;第二类为标注的标签&#xff0c;数据保存在xlsx的表格中&#xff0c;分为训练集和验证集。 textCNN 直接上整个工程代码&#xff1a; import pandas as pd import numpy as np import torch from torch.util…

SAPUI5基础知识3 - 引导过程(Bootstrap)

1. 背景 在上一篇博客中&#xff0c;我们已经建立出了第一个SAPUI5项目&#xff0c;接下来&#xff0c;我们将为这个项目添加引导过程。 在动手练习之前&#xff0c;让我们先解释一下什么引导过程。 1.1 什么是引导过程&#xff1f; 在计算机科学中&#xff0c;引导过程也称…

Presto 从提交SQL到获取结果 源码详解(3)

物理执行计划 回到SqlQueryExecution.startExecution() &#xff0c;执行计划划分以后&#xff0c; // 初始化连接&#xff0c;获取Connect 元数据&#xff0c;添加会话&#xff0c;初始ConnectId metadata.beginQuery(getSession(), plan.getConnectors()); // 构建物理执行…