【Java集合一】集合概述

一、集合简介

Java 集合框架(Collection Framework)是 Java 提供的一组用于存储和操作对象的类和接口集合。这些集合类提供了不同的数据结构,使得数据的管理和操作更加方便和高效。

Java 集合框架提供了各种类型的数据结构,如列表(List)、集合(Set)、映射(Map)等,以便开发人员能够更有效地管理和操作数据。

Java集合大致框架图如下:

具体关系图如下:

Collection 接口的接口 对象的集合(单列集合)
├——- List 接口:元素按进入先后有序保存,可重复
│—————-├ LinkedList 接口实现类, 基于链表, 优势在于插入删除,线程不安全
│—————-├ ArrayList 接口实现类, 基于数组, 优势在于随机访问,线程不安全
│—————-└ Vector 接口实现类 ,基于数组,线程安全
│ ———————-└ Stack 是Vector类的实现类
└——- Set 接口: 仅接收一次,不可重复,并做内部排序
├—————-└ HashSet 使用hash表(数组)存储元素
│————————└ LinkedHashSet 链表维护元素的插入次序
└ —————- TreeSet 底层实现为二叉树,元素排好序
└——- Queue 接口: 队列,通常用于存储和处理元素的顺序。
│—————-├ LinkedList 接口实现类, 链表, 优势在于插入删除, 线程不安全
│—————-├ PriorityQueue 接口实现类, 优先级队列, 不允许空值, 线程不安全
Map 接口 键值对的集合 (双列集合)
├——— Hashtable 接口实现类,线程安全
├——— HashMap 接口实现类 ,线程不安全
├——— ConcurrentHashMap 接口实现类 ,线程安全
│—————–├ LinkedHashMap 双向链表和哈希表实现
│—————–└ WeakHashMap
├ ——– TreeMap 红黑树对所有的key进行排序
└——— IdentifyHashMap

1.1 Collection 接口

Collection 是最基本的集合接口,声明了适用于JAVA集合(只包括Set和List)的通用方法。

Collection接口的方法:
  • boolean add(Object o); //向集合中加入一个对象的引用
  • void clear(); //删除集合中所有的对象,即不再持有这些对象的引用
  • boolean isEmpty(); //判断集合是否为空
  • boolean contains(Object o); //判断集合中是否持有特定对象的引用
  • boolean remove(Object o); //从集合中删除一个对象的引用
  • int size(); //返回集合中元素的数目
  • Iterartor iterator(); //返回一个Iterator对象,可以用来遍历集合中的元素
  • Object[] toArray(); //返回一个数组,该数组中包括集合中的所有元素
  • Stream stream(); //返回一个以集合为源的流,jdk1.8新加的

二、List

List 接口是 Collection 接口的子接口,表示一个有序的集合,允许存储重复元素。List 接口的实现类提供了按索引访问元素、插入元素、删除元素等操作,是一种常用的数据结构。

主要特点:
  • 有序性:List 接口维护了元素的插入顺序,可以按照元素在列表中的位置来访问和操作元素,插入的顺序即输出的顺序。
  • 允许存储重复元素:与 Set 不同,List 允许在列表中存储相同的元素。
  • 允许元素为空:可以插入多个null元素。
  • 可通过索引访问元素:List 接口提供了根据索引访问元素的方法,例如 get(int index) 和 set(int index, E element)。
List接口主要提供了以下方法:
  • void add(int index, E element) :在指定索引位置插入元素。
  • E get(int index) :获取指定索引位置的元素。
  • E set(int index, E element) :将指定索引位置的元素替换为新的元素。
  • int indexOf(Object o) :返回指定元素在列表中第一次出现的索引。
  • int lastIndexOf(Object o) :返回指定元素在列表中最后一次出现的索引。
  • E remove(int index) :移除指定索引位置的元素。
List的接口有三个实现类。
  • ArrayList:基于数组实现的 List,适合随机访问元素
    • 优点: 底层数据结构是数组,查询快,增删慢。
    • 缺点: 线程不安全(一般不考虑到线程的安全因素,用Arraylist效率比较高)
  • LinkedList:基于链表实现的 List,适合频繁插入、删除操作。
    • 优点: 底层数据结构是链表,增删快,查询慢。
    • 缺点: 线程不安全。
  • Vector:线程安全的 List,较少在现代代码中使用。
    • 优点: 底层数据结构是数组,查询快,增删慢。线程安全。
    • 缺点: 效率低(相比 ArrayList 线程不安全的,性能会稍慢一些)。

2.1 ArrayList

ArrayList 是 Java 中的 List 接口的一个常见实现类,它基于数组实现动态数组,可以根据需要动态增加其大小。ArrayList 提供了一系列方法来操作元素,是 Java 集合框架中最常用的数据结构之一。ArrayList 线程不安全。

特点和优势
  • 动态数组:ArrayList 内部使用数组来存储元素,可以根据需要动态增加其大小,而不需要手动处理数组扩容的问题。
  • 按索引访问:由于基于数组实现,ArrayList 可以通过索引快速访问元素,具有良好的随机访问性能。
  • 允许存储重复元素:与 Set 不同,ArrayList 允许在列表中存储相同的元素。
  • 允许元素为空:可以插入多个null元素。
  • 易于使用:ArrayList 提供了丰富的操作方法,如添加元素、删除元素、获取元素等,使用方便。
构造方法:
  1. ArrayList() :创建一个空的 ArrayList,当第一次add时才会初始化初始容量为 10。
  2. ArrayList(int initialCapacity) :创建一个具有指定初始容量的 ArrayList。
  3. ArrayList(Collectionc) :使用指定 collection 中的元素来构造一个 ArrayList。

示例代码:

import java.util.ArrayList;
import java.util.List;public class ArrayListExample {public static void main(String[] args) {List<String> fruits = new ArrayList<>();fruits.add("Apple");fruits.add("Banana");fruits.add("Orange");System.out.println("Size of the list: " + fruits.size());fruits.remove(1);for (String fruit : fruits) {System.out.println(fruit);}}
}

2.2 LinkedList

LinkedList 是 Java 中 List 接口的另一个常见实现类,它使用双向链表实现数据存储。与 ArrayList 基于数组实现不同,LinkedList 通过节点之间的引用来连接各个元素,适合频繁插入、删除操作的场景。LinkedList 线程不安全。

特点和优势:
  • 双向链表:LinkedList 内部使用双向链表来存储元素,每个节点包含对前一个和后一个元素的引用,便于在列表中进行插入和删除操作。
  • 插入和删除效率高:由于基于链表实现,插入和删除操作的效率比较高,不需要像数组那样涉及数据的搬移。
  • 支持高效的迭代:LinkedList 实现了 List 接口和 Queue 接口,可以作为队列或栈来使用,并且支持高效的迭代操作。
  • 占用更多内存:相比于 ArrayList,LinkedList 的每个节点都需要额外的空间存储指向前后节点的引用,可能占用更多的内存
构造方法:
  1. LinkedList() :创建一个空的 LinkedList。
  2. LinkedList(Collectionc) :创建一个包含指定集合中的元素的 LinkedList,这样就可以通过将现有集合传递给构造函数来初始化 LinkedList。

示例代码:

import java.util.LinkedList;
import java.util.List;public class LinkedListExample {public static void main(String[] args) {List<String> animals = new LinkedList<>();animals.add("Dog");animals.add("Cat");animals.add("Elephant");System.out.println("Size of the list: " + animals.size());animals.remove(1);for (String animal : animals) {System.out.println(animal);}}
}

三、Set

Set 接口继承自 Collection 接口,因此它具有 Collection 接口定义的大部分方法,同时又添加了不能包含重复元素的特性。

特点和优势:
  • 不包含重复元素:Set 中不允许包含重复的元素,每个元素在 Set 中都是唯一的。
  • 允许空元素:允许一个空元素。
  • 无序性:Set 不保证元素的顺序,即元素存储的顺序和插入的顺序不一定相同,但可以使用特定的实现类如 TreeSet 来维护元素的排序状态。
  • 常用实现类:Java 中常见的 Set 接口的实现类包括 HashSet、TreeSet 和 LinkedHashSet。
  • 用途广泛:由于其元素不重复的特性,Set 通常用于需要确保元素唯一性的场景,例如去重操作、查找某个元素是否存在等。
主要方法:
  • boolean add(E e) :向 Set 中添加一个元素,如果该元素已经存在,则不会添加并返回 false。
  • boolean contains(Object o) :判断 Set 中是否包含指定的元素。
  • boolean remove(Object o) :从 Set 中移除指定的元素。
  • int size() :返回 Set 中的元素个数。
  • boolean isEmpty() :判断 Set 是否为空。

3.1 HashSet

HashSet 是 Java 中 Set 接口的一个常见实现类,它基于哈希表实现。HashSet 不保证集合中元素的顺序,允许包含 null 元素,但不是线程安全的。

特点和优势
  • 不包含重复元素:与 Set 接口一致,HashSet 保证集合中不包含重复的元素,每个元素在 HashSet 中是唯一的。
  • 基于哈希表:HashSet 内部使用哈希表来存储元素,这使得查找、插入和删除操作具有很高的性能。
  • 无序性:HashSet 不保证元素的顺序,即元素存储的顺序和插入的顺序不一定相同。
  • 允许 null 元素:HashSet 允许包含一个 null 元素。
构造方法:
public HashSet() {map = new HashMap<>();
}public HashSet(Collection<? extends E> c) {map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));addAll(c);
}public HashSet(int initialCapacity, float loadFactor) {map = new HashMap<>(initialCapacity, loadFactor);
}public HashSet(int initialCapacity) {map = new HashMap<>(initialCapacity);
}//在LinkedHashSet的构造方法中调用
HashSet(int initialCapacity, float loadFactor, boolean dummy) {map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
主要方法
  • boolean add(E e) :向 HashSet 中添加一个元素,如果该元素已经存在,则不会添加并返回 false。
  • boolean contains(Object o) :判断 HashSet 中是否包含指定的元素。
  • boolean remove(Object o) :从 HashSet 中移除指定的元素。
  • int size() :返回 HashSet 中的元素个数。
  • boolean isEmpty() :判断 HashSet 是否为空。

示例代码:

import java.util.HashSet;
import java.util.Set;public class HashSetExample {public static void main(String[] args) {Set<String> fruitSet = new HashSet<>();fruitSet.add("Apple");fruitSet.add("Banana");fruitSet.add("Orange");System.out.println("Size of the set: " + fruitSet.size());fruitSet.remove("Banana");for (String fruit : fruitSet) {System.out.println(fruit);}}
}

3.2 TreeSet

TreeSet 是 Java 中 Set 接口的另一个常见实现类,它基于红黑树(Red-Black tree)实现。TreeSet 通过红黑树保证了集合元素的有序性,并且不允许包含 null 元素。
特点和优势:
  • 不包含重复元素:与 Set 接口一致,TreeSet 保证集合中不包含重复的元素,每个元素在 TreeSet 中是唯一的。
  • 有序性:TreeSet 通过红黑树实现,可以保证集合中的元素是有序的,通常是按照元素的自然顺序或者通过 Comparator 接口定义的比较规则进行排序。
  • 基于红黑树:红黑树是一种自平衡的二叉搜索树,能够保持高效的插入、删除和查找操作。
  • 不允许 null 元素:TreeSet 不允许包含 null 元素,否则会抛出 NullPointerException 异常。
构造方法:
public TreeSet() {this(new TreeMap<E,Object>());
}TreeSet(NavigableMap<E,Object> m) {this.m = m;
}public TreeSet(Comparator<? super E> comparator) {this(new TreeMap<>(comparator));
}public TreeSet(Collection<? extends E> c) {this();addAll(c);
}public TreeSet(SortedSet<E> s) {this(s.comparator());addAll(s);
}
主要方法:
  • boolean add(E e) :向 TreeSet 中添加一个元素,如果该元素已经存在,则不会添加并返回 false。
  • boolean contains(Object o) :判断 TreeSet 中是否包含指定的元素。
  • boolean remove(Object o) :从 TreeSet 中移除指定的元素。
  • int size() :返回 TreeSet 中的元素个数。
  • boolean isEmpty() :判断 TreeSet 是否为空。
示例代码:
import java.util.TreeSet;public class TreeSetExample {public static void main(String[] args) {// 创建一个TreeSet,元素自然排序(升序)TreeSet<Integer> numbers = new TreeSet<>();// 添加一些元素numbers.add(5);numbers.add(3);numbers.add(8);numbers.add(1);// 打印整个TreeSetSystem.out.println("TreeSet: " + numbers);// 查找是否存在某个元素System.out.println("Contains 6: " + numbers.contains(6));// 删除一个元素numbers.remove(3);System.out.println("TreeSet after removing 3: " + numbers);// 遍历TreeSetSystem.out.println("Traversing TreeSet:");for (int number : numbers) {System.out.println(number);}// 排序和检索操作System.out.println("First element: " + numbers.first());System.out.println("Last element: " + numbers.last());System.out.println("Element greater than 4: " + numbers.higher(4));System.out.println("Element lower than 4: " + numbers.lower(4));}
}

四、Queue

Queue 接口是 Java 集合框架中定义的一个接口,它代表了一种队列数据结构,遵循先进先出(FIFO)的原则。Queue 接口继承自 Collection 接口,提供了用于操作队列的方法。

主要方法:
  • 添加元素:
    • boolean add(E e) :将指定元素插入队列,如果队列已满则抛出异常。
    • boolean offer(E e) :将指定元素插入队列,如果队列已满则返回 false。
  • 获取并移除元素:
    • E remove() :获取并移除队列的头部元素,如果队列为空则抛出异常。
    • E poll() :获取并移除队列的头部元素,如果队列为空则返回 null。
  • 获取但不移除元素:
    • E element() :获取但不移除队列的头部元素,如果队列为空则抛出异常。
    • E peek() :获取但不移除队列的头部元素,如果队列为空则返回 null。
  • 其他方法:
    • int size() :返回队列中的元素个数。
    • boolean isEmpty() :判断队列是否为空。
常见实现类
  • LinkedList:实现了 Queue 接口,可以作为队列使用。
  • ArrayDeque:同样也实现了 Queue 接口,是一个基于数组实现的双端队列,可以作为队列使用。
  • PriorityQueue:优先级队列
应用场景
Queue 接口在 Java 中有许多实际的应用场景,特别是在需要进行异步处理、任务调度、消息传递等方面。以下是一些常见的 Queue 接口的应用场景:
  • 任务调度:在多线程编程中,可以使用队列来实现任务调度,将需要执行的任务按照一定的顺序或优先级放入队列中,然后由工作线程按照队列的顺序依次取出并执行这些任务。
  • 消息传递:在消息队列(Message Queue)系统中,消息被发送者放入队列,接收者从队列中获取消息并处理。这种方式可以实现解耦和异步通信,常见的消息队列如 RabbitMQ、Kafka 等都是基于队列的实现。
  • 生产者消费者模式:队列常常用于实现生产者消费者模式,生产者向队列中放入数据,消费者从队列中取出数据并进行处理,实现了生产和消费的解耦。
  • 线程池任务管理:线程池通常使用队列来存储待执行的任务,任务提交到线程池后会被放入队列中等待执行,线程池中的线程会从队列中取出任务并执行。
  • 网络爬虫:在网络爬虫程序中,可以使用队列来存储待访问的 URL,爬虫程序从队列中取出 URL 进行访问和解析,将新发现的 URL 放回队列中继续爬取。
  • 事件驱动编程:使用事件队列可以实现事件驱动编程模型,将事件按顺序放入队列中,然后由事件处理器逐个处理这些事件。

4.1 ArrayDeque

ArrayDeque 是一个基于数组实现的双端队列,为了满足可以同时在数组两端插入或删除元素的需求,数组必须是循环的,也就是说数组的任何一点都可以被看作是起点或者终点。

这是一个包含了 4 个元素的双端队列,和一个包含了 5 个元素的双端队列:

 head 指向队首的第一个有效的元素,tail 指向队尾第一个可以插入元素的空位,因为是循环数组,所以 head 不一定从是从 0 开始,tail 也不一定总是比 head 大。

4.2 PriorityQueue

PriorityQueue 是一种优先级队列,它的出队顺序与元素的优先级有关,执行 remove 或者 poll 方法,返回的总是优先级最高的元素。要想有优先级,元素就需要实现 Comparable 接口或者 Comparator 接口。

五、Map

Map 接口代表着一种映射关系,用来存储键值对。每个键都是唯一的,而值则可以重复。Map 接口提供了将键映射到值的功能,同时也允许通过键来检索对应的值。

特点:
  • 键值对映射:Map 中的数据以键值对的形式存储,每个键都与一个值相关联。
  • 键的唯一性:Map 中的键是唯一的,同一个键只能对应一个值。
  • 值的重复性:Map 中的值可以重复,不同的键可以映射到相同的值。
  • 键和值均可为 null:Map 中的键和值都可以为 null。
  • 实现类可以根据需求选择:Java 提供了多个实现 Map 接口的类,如 HashMap、TreeMap、LinkedHashMap、ConcurrentHashMap 等,每种实现类都有自己的特点和适用场景。
主要方法:
  • void clear() :清空 Map 中的所有键值对。
  • boolean containsKey(Object key) :判断 Map 中是否包含指定的键。
  • boolean containsValue(Object value) :判断 Map 中是否包含指定的值。
  • V get(Object key) :获取指定键对应的值。
  • boolean isEmpty() :判断 Map 是否为空。
  • SetkeySet() :返回包含所有键的 Set 集合。
  • V put(K key, V value) :向 Map 中添加键值对。
  • V remove(Object key) :移除指定键对应的键值对。
  • int size() :返回 Map 中键值对的数量。
  • Collectionvalues() :返回包含所有值的 Collection 集合。

5.1 HashMap (重点)

HashMap 是 Java 中最常用的 Map 接口的实现类之一,它基于哈希表实现,提供了快速的插入、删除和查找操作。

特点:
  • 基于哈希表:HashMap 内部通过哈希表来存储键值对,通过哈希算法可以快速定位到存储位置,实现了常数时间复杂度的插入、删除和查找操作。
  • 允许键和值为 null:HashMap 允许键和值都为 null,且可以有一个 null 键和多个 null 值。
  • 非线程安全:HashMap 是非线程安全的,如果需要在多线程环境下使用,可以考虑使用 ConcurrentHashMap。
  • 无序性:HashMap 不保证键值对的顺序,即插入顺序不会影响元素的遍历顺序。
  • 初始容量和加载因子:HashMap 可以指定初始容量和负载因子,加载因子表示哈希表在 rehashing(扩容)之前可以达到多满的程度,默认负载因子为 0.75。
  • 迭代器:HashMap 提供了迭代器(Iterator)来遍历键值对。
HashMap 类有多个构造方法,主要用于创建不同初始容量和加载因子的 HashMap 对象:
  • HashMap() :默认构造方法创建一个初始容量为 16,加载因子为 0.75 的空 HashMap。
  • HashMap(int initialCapacity) :创建一个指定初始容量,加载因子为 0.75 的空 HashMap。
  • HashMap(int initialCapacity, float loadFactor) :创建一个指定初始容量和加载因子的空 HashMap。
  • HashMap(Mapm) :使用指定 Map 中的键值对创建一个新的 HashMap。新 HashMap 的容量为原 Map 的两倍。
方法:
  • put(K key, V value) :将指定的键值对存储到 HashMap 中。
  • get(Object key) :获取指定键对应的值。
  • remove(Object key) :移除指定键对应的键值对。
  • containsKey(Object key) :判断是否包含指定的键。
  • size() :返回 HashMap 中键值对的数量。
  • keySet() :返回包含所有键的 Set 集合。
  • values() :返回包含所有值的 Collection 集合。​​
原理概述:
  • HashMap 底层通过数组、链表、红黑树组合实现。数组被称为“桶”(buckets),每个桶存储一个链表或者一个红黑树,桶位置的节点为链表或红黑树的头结点。
  • HashMap 根据 key 的 hashCode 值来确定其存储位置,通过 hashCode 来快速定位到对应的桶。
    • hash :h = key.hashCode()) ^ (h >>> 16) hashcode与hashcode右移16位做异或运算,为了使hashcode的高位也参加运算,使key充分散列
    • i = (n - 1) & hash 通过hash值计算出桶的位置
  • hashCode 和 equals 方法:
    • 在 HashMap 中,key 的 hashCode 用于确定其在数组中的索引位置。
    • 如果两个 key 的 hashCode 相同,HashMap 会使用 equals 方法来进一步判断它们是否相等。
  • 解决哈希冲突:
    • 当不同的 key 计算出相同的 hashCode 值时,就会发生哈希冲突。
    • HashMap 使用链表或红黑树来存储具有相同 hashCode 的 key-value 对,以解决哈希冲突。
    • 当链表长度过长(默认超过8个节点),链表会转换为红黑树,以提高检索效率。
  • 扩容与负载因子:
    • 当 HashMap 中的元素个数超过负载因子(默认为 0.75 * 容量)时,HashMap 会进行扩容操作。
    • 扩容会创建一个新的更大的数组(2倍扩容:newCap = oldCap << 1),并将原数组中的元素重新分配到新数组中,以减少哈希碰撞。
  • 迭代顺序:
    • HashMap 的遍历顺序并不是按照插入顺序或者自然顺序,而是根据 key 的 hashCode 来确定顺序。
    • 因此,HashMap 中的元素遍历顺序是不确定的,不同的运行环境可能会有不同的遍历顺序。
  • 线程安全性:
    • HashMap 在多线程环境下不是线程安全的,如果需要在多线程环境中使用,可以考虑使用 ConcurrentHashMap。

5.2 ConcurrentHashMap(重点)

ConcurrentHashMap是J.U.C(java.util.concurrent包)的重要成员,它是HashMap的一个线程安全的、支持高并发的版本。

Map 接口的另一个实现类 Hashtable 虽然是线程安全的,但是执行效率很低。

JDK 1.7及之前版本: 采用分段锁(Segment):
  • 哈希表被分为多个段,每个段独立加锁。
  • 每个段是一个小的哈希表,有自己的锁。
  • 支持多个更新操作并行,只要它们发生在不同的段上。
JDK 1.8及之后版本: 废弃分段锁,采用 CAS 结合 synchronized 锁细化的桶来实现线程安全:
  • 哈希表的每个桶变得可以独立加锁。
  • 链表转红黑树 :当桶中的元素数量达到一定阈值时,链表结构将转变为红黑树,以减少搜索时间。
  • 锁分离技术: 读操作几乎不需要锁,写操作锁定的范围大大减少。结合 CAS 操作,提高了并发性能。
ConcurrentHashMap不仅仅是线程安全的,它还通过一系列精妙的设计实现了与效率的平衡:
  • 不允许null值:与HashMap相比,ConcurrentHashMap不允许键或值为null,这样设计可以避免并发情况下的歧义。
  • 高效的迭代器:ConcurrentHashMap的迭代器具有弱一致性,这意味着迭代器创建后的修改不一定能反映在它上面,但它们不会抛出ConcurrentModificationException异常。
  • 无锁读取:ConcurrentHashMap的获取操作通常不需要锁定或者只需要很小的同步开销(CAS操作)。
构造方法:
public class ConcurrentHashMap<K,V> extends AbstractMap<K,V> implements ConcurrentMap<K,V>, Serializable {//......public ConcurrentHashMap() {}public ConcurrentHashMap(int initialCapacity) {if (initialCapacity < 0)throw new IllegalArgumentException();int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?MAXIMUM_CAPACITY :tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));this.sizeCtl = cap;}public ConcurrentHashMap(int initialCapacity, float loadFactor) {this(initialCapacity, loadFactor, 1);}public ConcurrentHashMap(int initialCapacity,float loadFactor, int concurrencyLevel) {if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)throw new IllegalArgumentException();if (initialCapacity < concurrencyLevel)   // Use at least as many binsinitialCapacity = concurrencyLevel;   // as estimated threadslong size = (long)(1.0 + (long)initialCapacity / loadFactor);int cap = (size >= (long)MAXIMUM_CAPACITY) ?MAXIMUM_CAPACITY : tableSizeFor((int)size);this.sizeCtl = cap;}public ConcurrentHashMap(Map<? extends K, ? extends V> m) {this.sizeCtl = DEFAULT_CAPACITY;putAll(m);}
}

5.3 LinkedHashMap

LinkedHashMap​是Java中的一个类,它继承自HashMap​,并且保留了元素插入的顺序。

大多数情况下,只要不涉及线程安全问题,Map基本都可以使用HashMap,不过HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序。HashMap的这一缺点往往会带来困扰,因为有些场景,我们期待一个有序的Map。

于是 LinkedHashMap 就闪亮登场了。LinkedHashMap 是 HashMap 的子类,内部使用链表来记录插入/访问元素的顺序。

LinkedHashMap 可以看作是 HashMap + LinkedList 的合体,它使用了 哈希表来存储数据,又用了双向链表来维持顺序。

特点:
  • 保持插入顺序:LinkedHashMap​会记住元素的插入顺序,并且迭代时会按照插入顺序返回元素。
  • 内部采用双向链表维护顺序:在LinkedHashMap​内部,元素以双向链表连接起来,这样可以保证元素的有序性。
构造方法:
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> {//......//创建一个空的LinkedHashMap​,默认初始容量为16,负载因子为0.75public LinkedHashMap() {super();accessOrder = false;}//创建一个指定初始容量的LinkedHashMappublic LinkedHashMap(int initialCapacity) {super(initialCapacity);accessOrder = false;}//创建一个指定初始容量和负载因子的LinkedHashMappublic LinkedHashMap(int initialCapacity, float loadFactor) {super(initialCapacity, loadFactor);accessOrder = false;}public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {super(initialCapacity, loadFactor);this.accessOrder = accessOrder;}//创建一个包含指定映射中的所有映射关系的LinkedHashMappublic LinkedHashMap(Map<? extends K, ? extends V> m) {super();accessOrder = false;putMapEntries(m, false);}//......
}
主要方法:
  • put(K key, V value): 将键值对添加到LinkedHashMap​中。
  • get(Object key): 获取指定键对应的值。
  • remove(Object key): 移除指定键对应的映射关系。
  • clear(): 清空LinkedHashMap​中的所有映射关系。
  • keySet(): 返回包含所有键的Set视图。
  • entrySet(): 返回包含所有映射关系的Set视图。
示例代码:
// 创建一个LinkedHashMap实例
LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<>();// 向LinkedHashMap中添加元素
linkedHashMap.put("A", 1);
linkedHashMap.put("B", 2);
linkedHashMap.put("C", 3);// 遍历LinkedHashMap并打印键值对(按插入顺序)
for (Map.Entry<String, Integer> entry : linkedHashMap.entrySet()) {System.out.println(entry.getKey() + ": " + entry.getValue());
}// 输出结果将会按照插入顺序:
// A: 1
// B: 2
// C: 3

5.4 TreeMap

TreeMap 类是基于红黑树数据结构实现的有序映射(键值对)集合。它继承自 AbstractMap 类并实现了 NavigableMap 接口。TreeMap 通过红黑树实现了按键的自然顺序或自定义顺序排序,并且提供了一些额外的功能。

特点:
  • 有序性: TreeMap 中的键值对是根据键的自然顺序或者通过 Comparator 进行排序的。这使得 TreeMap 能够按照键的顺序进行遍历和范围查询。
  • 基于红黑树: TreeMap 内部使用红黑树作为数据结构来存储键值对,红黑树是一种自平衡的二叉搜索树,能够保持高效的插入、删除和查找操作。
  • 支持子视图: TreeMap 提供了多种方法来获取子视图,如 subMap()​, headMap()​, tailMap()​,可以方便地对 TreeMap 进行范围操作。
  • 性能: TreeMap 中的基本操作(插入、删除、查找)的时间复杂度为 O(log n),其中 n 为 TreeMap 中的元素个数。由于红黑树的自平衡性质,TreeMap 在大部分情况下能够保持较好的性能。
构造方法:
public class TreeMap<K,V> extends AbstractMap<K,V>implements NavigableMap<K,V>, Cloneable, java.io.Serializable {//......//创建一个空的TreeMap​,按照键的自然顺序进行排序public TreeMap() {comparator = null;}//创建一个空的TreeMap​,按照指定比较器进行排序public TreeMap(Comparator<? super K> comparator) {this.comparator = comparator;}//创建一个TreeMap​,其中包含指定映射中的所有映射关系public TreeMap(Map<? extends K, ? extends V> m) {comparator = null;putAll(m);}public TreeMap(SortedMap<K, ? extends V> m) {comparator = m.comparator();try {buildFromSorted(m.size(), m.entrySet().iterator(), null, null);} catch (java.io.IOException cannotHappen) {} catch (ClassNotFoundException cannotHappen) {}}//......
}
主要方法:
  • put(key, value)​:向 TreeMap 中插入键值对。
  • get(key)​:获取指定键对应的值。
  • remove(key)​:移除指定键及其对应的值。
  • containsKey(key)​:判断 TreeMap 是否包含指定的键。
  • size()​:返回 TreeMap 的大小(键值对数量)。
  • keySet()​:返回包含所有键的 Set 集合。
  • values()​:返回包含所有值的 Collection 集合。
  • entrySet()​:返回包含所有键值对的 Set 集合。
代码示例:
import java.util.TreeMap;public class TreeMapExample {public static void main(String[] args) {// 创建一个 TreeMap 实例TreeMap<String, Integer> treeMap = new TreeMap<>();// 向 TreeMap 中插入键值对treeMap.put("apple", 10);treeMap.put("banana", 20);treeMap.put("orange", 15);// 获取指定键对应的值System.out.println("The value of apple: " + treeMap.get("apple"));// 移除指定键及其对应的值treeMap.remove("banana");// 遍历 TreeMap 中的键值对for (String key : treeMap.keySet()) {System.out.println(key + ": " + treeMap.get(key));}// 创建一个空的TreeMap,按照指定比较器进行排序Comparator<String> customComparator = new CustomComparator(); // 假设CustomComparator是自定义的比较器TreeMap<String, Integer> treeMap2 = new TreeMap<>(customComparator);}
}

六、Iterator 迭代器

迭代器(Iterator)是 Java 集合框架中的一种机制,是一种用于遍历集合(如列表、集合和映射等)的接口。

它提供了一种统一的方式来访问集合中的元素,而不需要了解底层集合的具体实现细节。

由于每一个容器都有取出元素的功能。这些功能定义都一样,只不过实现的具体方式不同(因为每一个容器的数据结构不一样)所以对共性的取出功能进行了抽取,从而出现了 Iterator 接口。而每一个容器都在其内部对该接口进行了内部类的实现,也就是将取出方式的细节进行封装

如何获取迭代器?Collection 接口中定义了获取集合类迭代器的方法(iterator()),所以所有的 Collection 体系集合都可以获取自身的迭代器。

Iterator 是 Java 迭代器最简单的实现,ListIterator 继承扩展了 Iterator 接口:

迭代器接口定义了几个方法,最常用的是以下三个:
  • next() - 返回迭代器的下一个元素,并将迭代器的指针移到下一个位置。
  • hasNext() - 用于判断集合中是否还有下一个元素可以访问。
  • remove() - 从集合中删除迭代器最后访问的元素(可选操作)。
ListIterator 是 List专属的迭代器,对 Iterator 进行了扩展:
  • add(E e) 将指定的元素插入列表(可选操作)。该元素直接插入到 next 返回的下一个元素的前面(如果有)
  • void set(E o) 用指定元素替换 next 或 previous 返回的最后一个元素
  • hasPrevious() 逆向遍历列表,列表迭代器有多个元素,则返回 true。
  • previous() 返回列表中的前一个元素。

Iterator在迭代时,只能对元素进行获取(next())和删除(remove())的操作。

对于 Iterator 的子接口 ListIterator 在迭代list 集合时,还可以对元素进行添加 add(obj),修改set(obj) 操作,甚至还能倒序遍历。

6.1 Iterable

Collection 的父接口。实现了 Iterable 的类就是可迭代的,并且支持增强for循环。

Collection 接口继承了 Iterable ,所以 Collection 体系都具备获取自身迭代器的方法,只不过每个子类集合都进行了重写(因为数据结构不同)。

6.2 ArrayList#iterator()

ArrayList 实现的 Iterator ,源码如下:

public class ArrayList<E> extends AbstractList<E> {//......public Iterator<E> iterator() {return new Itr();}/*** An optimized version of AbstractList.Itr*/private class Itr implements Iterator<E> {int cursor;       // index of next element to returnint lastRet = -1; // index of last element returned; -1 if no suchint expectedModCount = modCount;Itr() {}public boolean hasNext() {return cursor != size;}@SuppressWarnings("unchecked")public E next() {checkForComodification();int i = cursor;if (i >= size)throw new NoSuchElementException();Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length)throw new ConcurrentModificationException();cursor = i + 1;return (E) elementData[lastRet = i];}public void remove() {if (lastRet < 0)throw new IllegalStateException();checkForComodification();try {ArrayList.this.remove(lastRet);cursor = lastRet;lastRet = -1;expectedModCount = modCount;} catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException();}}@Override@SuppressWarnings("unchecked")public void forEachRemaining(Consumer<? super E> consumer) {Objects.requireNonNull(consumer);final int size = ArrayList.this.size;int i = cursor;if (i >= size) {return;}final Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length) {throw new ConcurrentModificationException();}while (i != size && modCount == expectedModCount) {consumer.accept((E) elementData[i++]);}// update once at end of iteration to reduce heap write trafficcursor = i;lastRet = i - 1;checkForComodification();}final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}}//......
}

ArrayList 实现的 ListIterator ,源码如下:

public class ArrayList<E> extends AbstractList<E> {//......public ListIterator<E> listIterator() {return new ListItr(0);}private class ListItr extends Itr implements ListIterator<E> {ListItr(int index) {super();cursor = index;}public boolean hasPrevious() {return cursor != 0;}public int nextIndex() {return cursor;}public int previousIndex() {return cursor - 1;}@SuppressWarnings("unchecked")public E previous() {checkForComodification();int i = cursor - 1;if (i < 0)throw new NoSuchElementException();Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length)throw new ConcurrentModificationException();cursor = i;return (E) elementData[lastRet = i];}public void set(E e) {if (lastRet < 0)throw new IllegalStateException();checkForComodification();try {ArrayList.this.set(lastRet, e);} catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException();}}public void add(E e) {checkForComodification();try {int i = cursor;ArrayList.this.add(i, e);cursor = i + 1;lastRet = -1;expectedModCount = modCount;} catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException();}}}//......
}

可以看到 ArrayList 内部定义类 Iterator 的实现类 Itr ,以及 ListIterator 的实现类 ListItr。

6.3 迭代器遍历

1)while循环

public static void main(String[] args) {ArrayList list = new ArrayList();list.add("计算机网络");list.add("现代操作系统");list.add("java编程思想");list.add("java核心技术");list.add("java语言程序设计");Iterator it = list.iterator();while (it.hasNext()) {String next = (String) it.next();System.out.println(next);}
}

2)for循环

public static void main(String[] args) {ArrayList list = new ArrayList();// 增加:add() 将指定对象存储到容器中list.add("计算机网络");list.add("现代操作系统");list.add("java编程思想");list.add("java核心技术");list.add("java语言程序设计");for (Iterator it = list.iterator(); it.hasNext();) {//迭代器的next方法返回值类型是Object,所以要记得类型转换。String next = (String) it.next();System.out.println(next);}
}

注意:

  • 如果迭代器的指针已经指向了集合的末尾,那么如果再调用next()会返回NoSuchElementException异常
  • 如果调用remove之前没有调用next是不合法的,会抛出IllegalStateException
  • 在用迭代器对集合进行迭代过程中,不允许出现迭代器以外的对元素的操作,因为这样会产生安全隐患,java会抛出异常并发修改异常(ConcurrentModificationException),普通迭代器 Iterator 只支持在迭代过程中的 remove() 删除操作。如果是List集合,想要在迭代中操作元素可以使用List集合的特有迭代器ListIterator,该迭代器支持在迭代过程中,添加元素和修改元素。

使用ListIterator 遍历List:

public static void main(String[] args) {ArrayList list = new ArrayList();list.add("计算机网络");list.add("现代操作系统");list.add("java编程思想");list.add("java核心技术");list.add("java语言程序设计");// 获取List专属的迭代器ListIterator lit = list.listIterator();//正序遍历while (lit.hasNext()) {String next = (String) lit.next();System.out.println(next);}System.out.println("***************");//倒序遍历while (lit.hasPrevious()) {String next = (String)lit.previous();System.out.println(next);}
}

七、集合工具类

7.1 Collections

Collections 是 JDK 提供的一个工具类,位于 java.util 包下,提供了一系列的静态方法,方便我们对集合进行各种骚操作,算是集合框架的一个大管家。

常用方法如下。

7.1.1 排序操作

  • reverse(List list)​:反转顺序
  • shuffle(List list)​:洗牌,将顺序打乱
  • sort(List list)​:自然升序
  • sort(List list, Comparator c)​:按照自定义的比较器排序
  • swap(List list, int i, int j)​:将 i 和 j 位置的元素交换位置
List<String> list = new ArrayList<>();
list.add("沉默王二");
list.add("沉默王三");
list.add("沉默王四");
list.add("沉默王五");
list.add("沉默王六");System.out.println("原始顺序:" + list);// 反转
Collections.reverse(list);
System.out.println("反转后:" + list);// 洗牌
Collections.shuffle(list);
System.out.println("洗牌后:" + list);// 自然升序
Collections.sort(list);
System.out.println("自然升序后:" + list);// 交换
Collections.swap(list, 2,4);
System.out.println("交换后:" + list);//结果打印
原始顺序:[沉默王二, 沉默王三, 沉默王四, 沉默王五, 沉默王六]
反转后:[沉默王六, 沉默王五, 沉默王四, 沉默王三, 沉默王二]
洗牌后:[沉默王五, 沉默王二, 沉默王六, 沉默王三, 沉默王四]
自然升序后:[沉默王三, 沉默王二, 沉默王五, 沉默王六, 沉默王四]
交换后:[沉默王三, 沉默王二, 沉默王四, 沉默王六, 沉默王五]

7.1.2 查找替换

  • binarySearch(List list, Object key)​:二分查找法,前提是 List 已经排序过了
  • max(Collection coll)​:返回最大元素
  • max(Collection coll, Comparator comp)​:根据自定义比较器,返回最大元素
  • min(Collection coll)​:返回最小元素
  • min(Collection coll, Comparator comp)​:根据自定义比较器,返回最小元素
  • fill(List list, Object obj)​:使用指定对象填充
  • frequency(Collection c, Object o)​:返回指定对象出现的次数
System.out.println("最大元素:" + Collections.max(list));
System.out.println("最小元素:" + Collections.min(list));
System.out.println("出现的次数:" + Collections.frequency(list, "沉默王二"));// 没有排序直接调用二分查找,结果是不确定的
System.out.println("排序前的二分查找结果:" + Collections.binarySearch(list, "沉默王二"));
Collections.sort(list);
// 排序后,查找结果和预期一致
System.out.println("排序后的二分查找结果:" + Collections.binarySearch(list, "沉默王二"));Collections.fill(list, "沉默王八");
System.out.println("填充后的结果:" + list);//结果打印
原始顺序:[沉默王二, 沉默王三, 沉默王四, 沉默王五, 沉默王六]
最大元素:沉默王四
最小元素:沉默王三
出现的次数:1
排序前的二分查找结果:0
排序后的二分查找结果:1
填充后的结果:[沉默王八, 沉默王八, 沉默王八, 沉默王八, 沉默王八]

7.1.3 checkedxxx 检查集合

返回类型检查的集合,在对类型进行set 或者add的时候会做类型检查。

public static void main(String[] args) {ArrayList list = Lists.newArrayList();list.add(new Player("香菜"));//  返回的safeList 在add时会进行类型检查List safeList = Collections.checkedList(list, Player.class);//此时会对类型进行检查,不是Player类型,抛出异常 java.lang.ClassCastException:safeList.add("xxx");
}

7.1.4 emptyxxx 返回空的集合

用这个方法的好处在于:
  • 不用处理返回null的问题。
  • 不用新生成空的list,避免占用内存,因为返回的空list,整个应用共同用一个(statics final修饰)。

7.1.5 synchronizedxxx 同步集合

ArrayList<Player> list = Lists.newArrayList();
//  TODO;-----
List<Player> synList = Collections.synchronizedList(list);

SynchronizedList 为 Collections 的内部类,源码如下:

static class SynchronizedList<E> extends SynchronizedCollection<E>implements List<E> {private static final long serialVersionUID = -7754090372962971524L;final List<E> list;SynchronizedList(List<E> list) {super(list);this.list = list;}SynchronizedList(List<E> list, Object mutex) {super(list, mutex);this.list = list;}public boolean equals(Object o) {if (this == o)return true;synchronized (mutex) {return list.equals(o);}}public int hashCode() {synchronized (mutex) {return list.hashCode();}}public E get(int index) {synchronized (mutex) {return list.get(index);}}public E set(int index, E element) {synchronized (mutex) {return list.set(index, element);}}public void add(int index, E element) {synchronized (mutex) {list.add(index, element);}}public E remove(int index) {synchronized (mutex) {return list.remove(index);}}//......
}

可以看到,实际相当于对集合进行了二次包装,在内部加了一把锁。

7.1.6 unmodifiableXxx 不可变集合

传入的集合返回后不可以改变。

ArrayList<Player> list = Lists.newArrayList();
//  TODO;-----
List<Player> synList = Collections.unmodifiableList(list);

UnmodifiableList 为 Collections 的内部类,源码如下:

static class UnmodifiableList<E> extends UnmodifiableCollection<E>implements List<E> {private static final long serialVersionUID = -283967356065247728L;final List<? extends E> list;UnmodifiableList(List<? extends E> list) {super(list);this.list = list;}public E get(int index) {return list.get(index);}public E set(int index, E element) {throw new UnsupportedOperationException();}public void add(int index, E element) {throw new UnsupportedOperationException();}public E remove(int index) {throw new UnsupportedOperationException();}public int indexOf(Object o)            {return list.indexOf(o);}public int lastIndexOf(Object o)        {return list.lastIndexOf(o);}public boolean addAll(int index, Collection<? extends E> c) {throw new UnsupportedOperationException();}@Overridepublic void replaceAll(UnaryOperator<E> operator) {throw new UnsupportedOperationException();}@Overridepublic void sort(Comparator<? super E> c) {throw new UnsupportedOperationException();}//......
}

可以看到,包装类屏蔽了集合的方法,抛出了异常。

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

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

相关文章

优选驾考小程序

第2章 系统分析 2.1系统使用相关技术分析 2.1.1Java语言介绍 Java语言是一种分布式的简单的 开发语言&#xff0c;有很好的特征&#xff0c;在安全方面、性能方面等。非常适合在Internet环境中使用&#xff0c;也是目前企业级运用中最常用的一个编程语言&#xff0c;具有很大…

什么是平面环形无影光源

平面环形无影光源是一种特殊设计的光源&#xff0c;主要用于消除阴影&#xff0c;提供均匀照明&#xff0c;常见于摄影、显微镜、工业检测等领域。以下是其关键特点和应用&#xff1a; 关键特点 环形设计&#xff1a;光源呈环形&#xff0c;光线从四周均匀照射&#xff0c;减少…

消息队列之-RabbitMq 学习

生产者服务A /消费者服务B 服务A和服务B配置: 依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency> yaml spring: rabbitmq:host: ${RABBITMQ_HOST:local…

vue 文件下载(导出)excel的方法

目前有一个到处功能的需求&#xff0c;这是我用过DeepSeek生成的导出&#xff08;下载&#xff09;excel的一个方法。 1.excel的文件名是后端生成的&#xff0c;放在了响应头那里。 2.这里也可以自己制定文件名。 3.axios用的是原生的axios&#xff0c;不要用处理过的&#xff…

Java NIO ByteBuffer 详解

什么是 ByteBuffer ByteBuffer 是 Buffer 的一个具体实现&#xff0c;专门用于存储和操作字节数据。它提供了高效的、基于内存的 I/O 数据处理方式。 Buffer 类是构建 Java NIO 的基础&#xff0c;其中 ByteBuffer 类是 Buffer 子类中最受欢迎的。这是因为字节类型是最通用的…

【大语言模型】最新ChatGPT、DeepSeek等大语言模型助力高效办公、论文与项目撰写、数据分析、机器学习与深度学习建模等科研应用

ChatGPT、DeepSeek等大语言模型助力科研应用 随着人工智能技术的快速发展&#xff0c;大语言模型如ChatGPT和DeepSeek在科研领域的应用正在为科研人员提供强大的支持。这些模型通过深度学习和大规模语料库训练&#xff0c;能够帮助科研人员高效地筛选文献、生成论文内容、进行数…

人工智能之数学基础:线性子空间

本文重点 在前面的课程中,我们学习了线性空间,本文我们我们在此基础上学习线性子空间。在应用中,线性子空间的概念被广泛应用于信号处理、机器学习、图像处理等领域。 子空间的性质 子空间是线性空间的一部分,它需要满足下面的性质: 设V是数域F上的线性空间,W是V的一个…

【清晰教程】本地部署DeepSeek-r1模型

【清晰教程】通过Docker为本地DeepSeek-r1部署WebUI界面-CSDN博客 目录 Ollama 安装Ollama DeepSeek-r1模型 安装DeepSeek-r1模型 Ollama Ollama 是一个开源工具&#xff0c;专注于简化大型语言模型&#xff08;LLMs&#xff09;的本地部署和管理。它允许用户在本地计算机…

deepseek部署在本地详细教程

最近&#xff0c;DeepSeek爆火&#xff0c;先进的算法、卓越的能力&#xff0c;表现出众&#xff0c;其凭一己之力推动国内Ai大模型跨越式发展。作为一款现象级的Ai产品&#xff0c;用户量暴增&#xff0c;最近服务器又被攻击&#xff0c;使用DeepSeek&#xff0c;经常出现服务…

DeepSeek v3 技术报告阅读笔记

注 本文参考 DeepSeek-v3 / v2 / v1 Technical Report 及相关参考模型论文本文不包括基础的知识点讲解&#xff0c;为笔记/大纲性质而非教程&#xff0c;建议阅读技术报告原文交流可发送至邮箱 henryhua0721foxmail.com 架构核心 核心&#xff1a; MLA 高效推理DeepSeekMOE 更…

浏览器安全学习

浏览器特性 会将一些特殊符号当做字母进行解析&#xff0c;此时一个符号可能会被解析成两个到三个字母&#xff0c;这样子如果有漏洞对输入做了限制&#xff0c;黑客就可以利用这个特性来绕过某些漏洞中长度限制。某些特殊字符或者其他国家的文字和某些字母的形状一模一样&…

2025年AI免费大战:从DeepSeek到GPT-5的商业逻辑与行业变革

引言&#xff1a;人工智能行业的2025年重大转折 2025年伊始&#xff0c;人工智能行业的竞争格局发生了深刻变化&#xff0c;尤其是以DeepSeek为代表的新兴力量&#xff0c;通过低成本开源策略迅速崛起&#xff0c;迫使OpenAI、百度文心一言等人工智能巨头纷纷调整策略&#xf…

Word写论文常用操作的参考文章

1.插入多个引用文献&#xff1a;word中交叉引用多篇参考文献格式[1-2]操作以及显示错误问题 更改左域名&#xff0c;输入 \#"[0" 更改右域名&#xff0c;输入 \#"0]" 2.插入题注&#xff1a;word 中添加图片题注、目录、内部链接 3.插入公式编号&#x…

国产化替代大势所趋,ARM工控机的未来之路

在全球技术竞争加剧和国家政策推动的背景下&#xff0c;中国正在经历一场前所未有的国产化替代浪潮。在这个过程中&#xff0c;基于ARM架构的工业控制计算机&#xff08;简称ARM工控机&#xff09;迎来了前所未有的发展机遇&#xff0c;同时也面临着诸多挑战。 机遇 技术创新驱…

uniapp商城之登录模块

文章目录 一、小程序快捷登录1.定义接口2.获取登录凭证 code3.获取手机号并登录 二、模拟快捷登录1.封装模拟登录API2.调用模拟登录 三、保存登录信息1.类型声明2.状态管理3.成功提示并跳转页面 一、小程序快捷登录 1.定义接口 2.获取登录凭证 code 3.获取手机号并登录 注意&a…

C++-----------酒店客房管理系统

酒店客房管理系统 要求&#xff1a; 1.客房信息管理:包括客房的编号、类型、价格、状态等信息的录入和修改; 2.顾客信息管理:包括顾客的基本信息、预订信息等的管理; 3.客房预订:客户可以根据需要进行客房的预订&#xff0c;系统会自动判断客房的可用情况; 4.入住管理:客户入住…

电动汽车电池监测平台系统设计(论文+源码+图纸)

1总体设计 本次基于单片机的电池监测平台系统设计&#xff0c;其整个系统架构如图2.1所示&#xff0c;其采用STC89C52单片机作为控制器&#xff0c;结合ACS712电流传感器、TLC1543模数转换器、LCD液晶、DS18B20温度传感器构成整个系统&#xff0c;在功能上可以实现电压、电流、…

2025年02月11日Github流行趋势

项目名称&#xff1a;unsloth 项目地址url&#xff1a;https://github.com/unslothai/unsloth项目语言&#xff1a;Python历史star数&#xff1a;27175今日star数&#xff1a;1024项目维护者&#xff1a;danielhanchen, shimmyshimmer, Erland366, Datta0, xyangk项目简介&…

[qt5学习笔记]用vs2022(msvc2017)+copilot进行QtWidgetsApplication源码解析

一直没深入了解qt&#xff0c;又一段时间没写qt&#xff0c;重新捡起来。 开发环境 本地vs2022(msvc2017, v14.30)先升级到最新版本&#xff0c;方便使用copilot。 参考 VS2022QT5环境搭建 下载 qt5.14.2 用vs的qt插件设置qt5.14.2x86路径&#xff0c;x64版本未安装。 创建一…

家里装修想用投影仪,如何选择?装修中应该注意什么?

越来越多的业主在装修的时候抛弃了传统的电视&#xff0c;采用投影仪。 和这些业主聊天&#xff0c;选用投影仪有两个目的&#xff0c;第1是把电视机拿掉&#xff0c;这样能让家里的小朋友不看电视&#xff0c;保护小朋友的眼睛。 第2是选用投影仪&#xff0c;幕布都会装的比较…