当前位置: 首页 > news >正文

Java集合(八股)

这里写目录标题

  • Collection 接口
    • List 接口
        • ArrayList 简述
      • 1. ArrayList 和 LinkedList 区别?⭐️⭐️⭐️⭐️
      • 2. ArrayList 和 Array 的区别?⭐️⭐️⭐️
      • ArrayList 和 Vector 区别?⭐️⭐️
      • ArrayList 的扩容机制?⭐️⭐️⭐️
    • Queue 接口
      • 1. Queue和Deque的区别?⭐️⭐️⭐️
      • 2. ArrayDeque与LinkedList区别?⭐️⭐️⭐️
      • 3. PriorityQueue有什么特点?⭐️⭐️⭐️
    • Set 接口
  • Map 接口
    • 简述HashMap
      • (1)HashMap查询、删除的时间复杂度⭐️⭐️⭐️⭐️
      • (2)HashMap的底层实现⭐️⭐️⭐️⭐️⭐️
    • 1. HashMap和HashTable的区别
    • 2. HashMap和HashSet区别⭐️⭐️⭐️⭐️
    • 3. HashMap和TreeMap的区别?⭐️⭐️⭐️⭐️
    • 4. CocurrentHashMap线程安全的具体实现方式/底层具体实现⭐️⭐️⭐️⭐️

!!!本文是基于javaGuide的学习和自我总结!!!

集合有两大接口CollectionMap,Collection中存单一元素,Map中存放kv对
from javaGuide
(图片 from javaGuide)

Collection 接口

List 接口

在这里插入图片描述

ArrayList 简述
public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable{...}

ArrayList
继承了AbstractList类;
实现了ListRandomAccessCloneableSerializable接口

  • List:表明他是一个列表,支持增删查等操作、
  • RandomAccess:表明List集合是支持快速随机访问
注:
这只是一个标志接口,不是实现了它就能快速随机访问,
还要看类的底层逻辑
(如LinkedList就算继承了RandomAccess,也无法实现随机访问,因为它底层是链表,内存地址是不连续的 , 所以注定不可能)
  • Cloneable:表明它具有拷贝能力,可以进行深拷贝和浅拷贝
  • Serializable:表明它可以进行序列化操作,也就是可以将对象转换为字节流进行持久化存储或网络传输

1. ArrayList 和 LinkedList 区别?⭐️⭐️⭐️⭐️

首先说明 :
貌似绝大多数情况都是使用ArrayList , 就算是需要用到LinkedList的情况 ,也是可以用ArrayList替代掉的 , 且性能会更好
在这里插入图片描述

  • 是否线程安全

都不是线程安全的,因为他俩都是不同步的(源码中没有任何“同步”的想法)

  • 底层数据结构
  • ArrayList 底层使用的是Object数组
  • ListedList 底层使用的是双向链表
  • 插入和删除是否受元素位置的影响
  • ArrayList 采用数组存储,所以插入和删除的时间复杂度 受元素位置的影响。
比如:
执行 `add(E e)`方法时,ArrayList会默认在末尾追加元素,时间复杂度是O(1)
执行`add(int index, E element)`,ArrayList会让第i个及以后元素 全部移动一位,时间复杂度是O(n)
  • ListedList 采用链表存储,插入、删除头尾元素不受影响,指定索引的插入删除操作受影响
执行`add(E e)` `addFirst(E e)``addLast(E e)``removeFirst()``removeLast()` 时间复杂度为O(1)
执行`add(int index, E element)` `remove(Object o)` `remove(int index)`时间复杂度为O(n),因为需要先移动到指定位置再插入和删除 
  • 是否支持快速随机访问

ArrayList 支持 --> 实现了RandomAccess的接口
ListedList不支持

  • 内存空间占用
  • ArrayList 的空间浪费主要体现在 : list列表结尾会预留一定容量的空间
  • LinkedList 的空间花费则体现在 : 每个元素都需要消耗比ArrayList更多的空间 (因为都要存放直接后继和直接前驱以及数据)

2. ArrayList 和 Array 的区别?⭐️⭐️⭐️

  • Array

Array(数组) 就是一个可以自定义固定长度数组 , 只能按照下标访问元素 , Array里面没有定义什么便于使用的方法
最常用的可能就是Array.length() 和 Array.sort()

  • ArrayList
    ArrayList<Integer> list = new ArrayList();

ArrayList 内置了丰富的API操作方法 , 比如add() , remove()等
它会根据实际存储的元素动态扩容
允许使用泛型 来确保类型安全
只能存储对象

ArrayList 和 Vector 区别?⭐️⭐️

它们底层都是使用Object()存储

  • Vector比较老了 , 但它是线程安全的(很少使用了)
  • ArrayList , 适用于频繁的查找工作 ; 线程不安全

ArrayList 的扩容机制?⭐️⭐️⭐️

  • ArrayList的默认长度是10,当然也可以自定义
  • 当数组存储的元素 数量大于10的时候,就会触发扩容机制(也就是grow()方法)
  • grow()方法 会创建一个新的数组,这个新数组的长度大约是原来的1.5倍(grow中的移位运算 算出来的)
  • 然后通过Arrays.copyOf()方法将老数组赋值到新数组当中
  • 以此类推

ArrayList的扩容机制的核心其实是grow()方法

/*** 要分配的最大数组大小*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;/*** ArrayList扩容的核心方法。*/
private void grow(int minCapacity) {// oldCapacity为旧容量,newCapacity为新容量int oldCapacity = elementData.length;// 将oldCapacity 右移一位,其效果相当于oldCapacity /2,// 我们知道位运算的速度远远快于整除运算,整句运算式的结果就是将新容量更新为旧容量的1.5倍,int newCapacity = oldCapacity + (oldCapacity >> 1);// 然后检查新容量是否大于最小需要容量,若还是小于最小需要容量,那么就把最小需要容量当作数组的新容量,if (newCapacity - minCapacity < 0)newCapacity = minCapacity;// 如果新容量大于 MAX_ARRAY_SIZE,进入(执行) `hugeCapacity()` 方法来比较 minCapacity 和 MAX_ARRAY_SIZE,// 如果minCapacity大于最大容量,则新容量则为`Integer.MAX_VALUE`,否则,新容量大小则为 MAX_ARRAY_SIZE 即为 `Integer.MAX_VALUE - 8`。if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);
}

Queue 接口

在这里插入图片描述

1. Queue和Deque的区别?⭐️⭐️⭐️

主要区别就是

Queue是单端队列
Deque是双端队列

本质上

  • Queue : public interface Queue<E> extends Collection<E> {...}
  • Deque : public interface Deque<E> extends Queue<E> {...}
  • Deque继承了Queue接口,并且扩展了在队头和队尾增删元素的方法
  • 事实上,Deque还提供有push()和pop()等其他方法,可用于模拟栈

2. ArrayDeque与LinkedList区别?⭐️⭐️⭐️

ArrayDeque和LinkedList都继承了Deque,两者有什么不同吗?

  • ArrayDeque
  1. ArrayDeque是基于可变数组和双指针实现的;LinkedList是基于链表实现
//ArrayDeque
transient Object[] elements;	//数组	
transient int head;	//头指针
transient int tail;	//尾指针
  1. ArrayDeque 不能添加null值,原因如下(源码);LinkedList可以
public void addFirst(E e) {if (e == null)throw new NullPointerException();elements[head = (head - 1) & (elements.length - 1)] >= e;if (head == tail)doubleCapacity();
}
  1. ArrayDeque是在jdk1.6才被引入的;LinkedList早就存在
  2. ArrayDeque 插入时存在扩容过程
  3. ArrayDeque性能更好

图片 from javaGuide
在这里插入图片描述

3. PriorityQueue有什么特点?⭐️⭐️⭐️

特点:元素出队顺序是与优先级相关的,即总是优先级最高的元素先出队

PriorityQueue会出现在手撕算法应用当中 --》堆排序、第K大的数、带权图的遍历等

Set 接口

Map 接口

在这里插入图片描述

简述HashMap

  • Map里面存放的是KV对,且Key值不可重复(这一点很重要,事关HashSet为啥不可重复,因为HashSet直接把值存到Key上了,Value则赋值为一个虚拟的Object对象)
  • 这篇文章很详细,不过比较老了:深入Java集合学习系列:HashMap的实现原理

(1)HashMap查询、删除的时间复杂度⭐️⭐️⭐️⭐️

  • 如果没有元素

处理:直接插入元素或者直接返回未找到
时间复杂度:O(1)

  • 如果有元素(链表)

处理:沿着链表遍历
时间复杂度:O(n)

  • 红黑树

时间复杂度O(longn)

(2)HashMap的底层实现⭐️⭐️⭐️⭐️⭐️

  1. 基于Map接口实现
public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable {...}
  1. 非线程安全
  2. HashMap的存储方法;解决哈希冲突
- JDK1.8之前,HashMap由 数组+链表 组成的,数组是HashMap的主题,链表则主要是为了解决哈希冲突而存在的(“拉链法”);
- JDK1.8以后得HashMap在解决哈希冲突时有了较大的变化,
-- 当链表的长度大于等于阈值(默认为8)时,
-- 会判断当前数组的长度是否小于64,
-- 如果小于64,则先进行数组扩容,
-- 如果大于64,则将链表转化为红黑树,以减少搜索时间
  1. HashMap默认初始化大小为16,之后每次扩充,容量变为原来的2倍。并且,HashMap总是使用2的幂作为哈希表的大小

1. HashMap和HashTable的区别

注 : HashTable基本被淘汰了

  • 线程安全

HashMap 线程不安全
HashTable 线程安全(HashTable内的方法基本都被synchronized修饰)

  • 效率

因为线程安全问题,所以HashTable的效率会低一些

  • 对Null key和Null value的支持

HashMap可以存储null的key和value,但null作为键只能有一个,null作为值可以有多个
HashTable不允许有null键和null值

  • 其他区别可以从上面写的HashMap来说(HashTable几乎不用了)

2. HashMap和HashSet区别⭐️⭐️⭐️⭐️

HashSet<Object> objects = new HashSet();
HashMap<Object, Object> objectObjectHashMap = new HashMap();
  • 区别:

HashMap里面存的是KV对 ;HashSet里存的是对象
HashMap的Key不可重复,Value可重复;HashSet不可重复
HashSet的add方法调用了HashMap中的put方法

// HashSet部分源码

public class HashSet<E>extends AbstractSet<E>implements Set<E>, Cloneable, java.io.Serializable
{static final long serialVersionUID = -5024744406713321676L;private transient HashMap<E,Object> map;// Dummy value to associate with an Object in the backing Mapprivate static final Object PRESENT = new Object();/*** Constructs a new, empty set; the backing <tt>HashMap</tt> instance has* default initial capacity (16) and load factor (0.75).*/public HashSet() {map = new HashMap<>();}...// 这里,调用了map的put方法,把e存到key上---》不能重复public boolean add(E e) {return map.put(e, PRESENT)==null;}
}

可以看出,HashSet底层就是基于HashMap实现的(HashSet的源码非常少,因为除了clone() , writeObject() , readObject() 是HashSet自己不得不实现之外,其他方法都是直接调用HashMap中的方法)

3. HashMap和TreeMap的区别?⭐️⭐️⭐️⭐️

相比于HashMap来说,TreeMap主要多了对集合中元素根据键排序以及对于集合内元素的搜索的能力

//HashMap

public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable {

//TreeMap

public class TreeMap<K,V>extends AbstractMap<K,V>implements NavigableMap<K,V>, Cloneable, java.io.Serializable
  • TreeMap实现了NavigableMap接口

实现NavigableMap接口让TreeMap有了对集合内元素的搜索能力

  • NavigableMap接口提供了丰富的方法来探索和操作键值对
  • TreeMap实现了SortedMap接口

实现SortedMap接口让TreeMap有了对集合中的元素根据键排序的能力。

  • 默认是按照key的升序排序,不过我们也可以指定排序的比较器

4. CocurrentHashMap线程安全的具体实现方式/底层具体实现⭐️⭐️⭐️⭐️

分两个阶段——jdk1.8之前;1.8及以后

  • jdk1.8以前
    在这里插入图片描述

首先将数据分成一段一段(这个“端”就是Segment)的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问

ConcurrentHashMap是由Segment数据结构和HashEntry数据结构组成

Segment的结构和1.8以前的HashMap类似
在这里插入图片描述

  • jdk1.8及以后
    在这里插入图片描述
    在这里插入图片描述

相关文章:

Java集合(八股)

这里写目录标题 Collection 接口List 接口ArrayList 简述 1. ArrayList 和 LinkedList 区别&#xff1f;⭐️⭐️⭐️⭐️2. ArrayList 和 Array 的区别&#xff1f;⭐️⭐️⭐️ArrayList 和 Vector 区别&#xff1f;⭐️⭐️ArrayList 的扩容机制&#xff1f;⭐️⭐️⭐️ Qu…...

python+adb

#!/usr/bin/python env # -*- coding: utf-8 -*- import os import sys import subprocess from time import sleepimport logging logging.basicConfig(levellogging.DEBUG) class ScreenCapture():def get_screen_size(self):"""获取手机分辨率""&q…...

AIGC文本生成

文本生成是一种人工智能技术&#xff0c;它基于深度学习算法&#xff0c;根据给定的提示信息创作出有逻辑、连贯的文本内容。 文本生成所需的输入&#xff08;提示或Prompt&#xff09;可以是简单的关键词、一句话概述或是更复杂的指令和上下文信息。文本生成模型通过分析大量…...

系统架构设计师教程 第5章 5.4 软件测试 笔记

5.4 软件测试 5.4.1 测试方法 ★★★★★ 软件测试方法的分类有很多种&#xff0c; 以测试过程中程序执行状态为依据可分为静态测试 (Static Testing,ST) 和动态测试 (Dynamic Testing,DT); 以具体实现算法细节和系统内部结构的相关情况为根据可分黑盒测试、白盒测试和灰盒测…...

ASPICE评估全流程解析:汽车软件开发组织能力的系统化评估

ASPICE&#xff08;Automotive SPICE&#xff09;评估的过程是一个系统化和详尽的流程&#xff0c;旨在评估汽车软件开发组织在软件开发过程方面的能力。 以下是ASPICE评估过程的详细描述&#xff1a; 1. 评估准备阶段 a. 确定评估目标和范围 明确评估的目标&#xff0c;如评…...

合并RAR分卷压缩包

因为文件压缩之后体积仍然过大&#xff0c;大家可能会选择进行分卷压缩&#xff0c;那么rar分卷压缩包之后如何合并成一个压缩包文件呢&#xff1f;今天我们来学习rar分卷压缩包&#xff0c;合并成一个的方法。 最基础的方法就是将分卷压缩包解压出来之后&#xff0c;再将文件…...

重生奇迹MU 想去哪就去哪玩 轻松玩转翅膀属性

在重生奇迹MU这个游戏中&#xff0c;玩家需要扫荡各种怪物&#xff0c;勇斗BOSS&#xff0c;与其他玩家激战。在这个充满冒险的旅程中&#xff0c;翅膀是最重要的装备之一。拥有一个属性强大的翅膀&#xff0c;代表着玩家的成长与强大。穿上它&#xff0c;加速你的冒险之旅吧&a…...

Lnux-gcc/g++使用

目录 1.gcc/g介绍 1.什么是 gcc / g 2.gcc/g指令格式 2. gcc / g 实现程序翻译的过程 1.预处理(进行宏替换) 2.编译(生成汇编&#xff09; 3.汇编&#xff08;生成机器可识别代码&#xff09; 4.连接&#xff08;生成可执行文件或库文件&#xff09; 1.gcc/g介绍 1.什么…...

用Python创建一个键盘输入捕获程序

目录 简介 环境准备 安装依赖 项目结构 编写代码 1. 导入库 2. 定义回调函数 3. 启动键盘监听器 4. 整合代码 运行程序 结论 简介 在这篇博文中,我们将探索如何使用Python编写一个简单的键盘输入捕获程序。这个程序将实时捕获用户的键盘输入并在控制台中显示出来。…...

Mybatis中Like模糊查询三种处理方式

目录 Mybatis中Like模糊查询三种处理方式 1.通过单引号拼接${} 1&#xff09;mapper接口 2&#xff09;Mapper.xml 3&#xff09;测试代码 4) 测试结果 2.通过concat()函数拼接(个人推荐使用这种) 1&#xff09;mapper接口 2&#xff09;Mapper.xml 3&#xff09;测试代码 4) 测…...

STL值list

list容器 头文件&#xff1a;#include<list> - list是一个双向链表容器&#xff0c;可高效地进行插入删除元素 - list不可以随机存取元素&#xff0c;所以不支持at.(pos)函数与[]操作符 注&#xff1a;list使用迭代器访问数据时可以一步一步走自增自减&#xff08;即…...

结构体的内存对齐

对⻬规则&#xff1a; 1.结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处 2.其他成员变量要对⻬到某个数字&#xff08;对⻬数&#xff09;的整数倍的地址处。 对⻬数编译器默认的⼀个对⻬数与该成员变量⼤⼩的较⼩值。 但一些编译器下并没有默认对其数 3.结…...

Web 创建设计

Web 创建设计 Web 创建设计是一个涉及多个方面的过程,它包括网站的视觉设计、用户界面设计、用户体验设计、前端开发以及后端开发等。本文将详细介绍这些方面,并探讨如何创建一个既美观又实用的网站。 1. 视觉设计 视觉设计是网站创建设计的第一步,它决定了网站的外观和感…...

2024年9月16日历史上的今天大事件早读

1151年9月16日 南宋名将韩世忠逝世 1782年9月16日 清朝道光帝旻宁出生 1810年9月16日 墨西哥独立日 1856年9月16日 云南杜文秀领导回民起义 1880年9月16日 左宗棠创办的兰州机器织呢局开工 1908年9月16日 美国通用汽车公司成立 1919年9月16日 周恩来组织参加的觉悟社成立…...

记录工作中遇到的问题(持续更新~)

跨域问题&#xff08;待排查&#xff09; 2024-09-15 【前提】&#xff1a;前端配置了nignx转发&#xff0c;后端设置了跨域拦截&#xff0c;对http://xxxx做了允许跨域。但是访问http://xxx被拦截了&#xff0c;返回403 Forbidden。同样的配置放在另外一套部署的环境上就完全…...

六西格玛咨询:石油机械制造企业的成本控制与优化专家

一、石油机械制造行业现状及主要困扰 随着全球能源需求的日益增长&#xff0c;石油开采和生产设备需求不断增加&#xff0c;石油机械制造行业在过去数十年里得到了迅猛发展。然而&#xff0c;石油机械制造作为一个高度复杂且技术密集的行业&#xff0c;也面临着多重挑战。首先…...

Redis基础数据结构之 quicklist 和 listpack 源码解读

目录标题 quicklist为什么要设计 quicklist&#xff1f;quicklist特点ziplist quicklist数据结构 listpacklistpack是什么&#xff1f;listpack数据结构ziplist干啥去了&#xff1f;为什么有listpack?什么是ziplist的连锁更新&#xff1f;listpack 如何避免连锁更新&#xff1…...

深入理解Go语言的方法定义与使用

在Go语言编程中&#xff0c;方法&#xff08;Method&#xff09; 是附属于特定类型的函数&#xff0c;使我们能够以面向对象的方式编写代码。通过方法&#xff0c;我们可以更自然地对类型进行操作。本文将通过实际的代码示例&#xff0c;深入探讨Go语言中方法的定义与使用。 一…...

堆排序,快速排序

目录 1.堆排序 2.快速排序 1.hoare版本 2.挖坑法 3.前后指针法 注意点 1.堆排序 void Swap(int* a, int* b) {int tmp *a;*a *b;*b tmp; } void adjustdown(int* a, int n, int parent) {int child parent * 2 1;while (child < n){if (child 1 < n &&am…...

系统架构师---数据库设计的四个阶段

需求分析、概念设计、逻辑设计和物理设计是数据库设计中的四个关键阶段&#xff0c;每个阶段都有其独特的任务和目标&#xff0c;以下是对这四个阶段的区别的详细阐述&#xff1a; 需求分析阶段 目标&#xff1a;全面理解用户对数据库系统的需求&#xff0c;包括业务需求、信…...

MySQL_简介及安装、配置、卸载(超详细)

课 程 推 荐我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448;入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448;虚 拟 环 境 搭 建 &#xff1a;&#x1…...

大数据处理技术:分布式文件系统HDFS

目录 1 实验名称&#xff1a; 2 实验目的 3 实验内容 4 实验原理 5 实验过程或源代码 5.1 HDFS的基本操作 5.2 HDFS-JAVA接口之读取文件 5.3 HDFS-JAVA接口之上传文件 5.4 HDFS-JAVA接口之删除文件 6 实验结果 6.1 HDFS的基本操作 6.2 HDFS-JAVA接口之读取文件 6.…...

组合数(模板)

1.杨辉三角求组合数&#xff0c;最高只能求几千内的组合数。 #include<bits/stdc.h> using namespace std; #define int long long int C[1005][1005]; signed main() {//求 1000 以内的组合数 for(int i0;i<1000;i){C[i][0]C[i][i]1;for(int j1;j<i;j){C[i][j]C[…...

时序数据库 TDengine 的入门体验和操作记录

时序数据库 TDengine 的学习和使用经验 什么是 TDengine &#xff1f;什么是时序数据 &#xff1f;使用RPM安装包部署默认的网络端口 TDengine 使用TDengine 命令行&#xff08;CLI&#xff09;taosBenchmark服务器内存需求删库跑路测试 使用体验文档纠错 什么是 TDengine &…...

Qt-QPushButton按钮类控件(22)

目录 描述 使用 给按钮添加图片 给按钮添加快捷键 添加槽函数 添加快捷键 添加组合键 开启鼠标的连发功能 描述 经过上面的一些介绍&#xff0c;我们也尝试的使用过了这个控件&#xff0c;接下来我们就要详细介绍这些比较重要的控件了 使用 给按钮添加图片 我们创建…...

镜舟科技与中启乘数科技达成战略合作,共筑数据服务新生态

当今企业数据管理日益规范化&#xff0c;数据应用系统随着数据类型与数量的增长不断细分&#xff0c;为了提升市场竞争力与技术实力&#xff0c;数据领域软件服务商与上下游伙伴的紧密对接与合作显得尤为重要。通过构建完善的生态系统&#xff0c;生态内企业间能够整合资源、共…...

蒸!--数据在内存中的存储

一.整数在内存中的存储 对于整形来说&#xff1a;数据存放内存中其实存放的是补码。 为什么&#xff1f; 在计算机系统中&#xff0c;数值⼀律⽤补码来表⽰和存储。 原因在于&#xff0c;使⽤补码&#xff0c;可以将符号位和数值域统⼀处理&#xff1b; 同时&#xff0c;加法和…...

利用AI增强现实开发:基于CoreML的深度学习图像场景识别实战教程

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…...

每个企业都需要 (但未使用) 的 BYOD 安全解决方案

远程办公模式的转变彻底改变了组织管理员工设备的方式。如今&#xff0c;员工希望能够灵活地在任何地方使用任何设备工作&#xff0c;这导致自带设备 (BYOD) 政策被广泛采用。 但随着越来越多的企业采用BYOD&#xff0c;一个问题依然摆在眼前&#xff1a;如何在不侵犯个人隐私…...

【多系统萎缩患者必看】科学锻炼秘籍,让生命之树常青

亲爱的小红书朋友们&#xff0c;&#x1f44b; 今天我们要聊一个温暖而坚韧的话题——关于多系统萎缩&#xff08;MSA&#xff09;患者的锻炼指南。在这个充满挑战的旅程中&#xff0c;锻炼不仅是身体的锻炼&#xff0c;更是心灵的滋养&#xff0c;是对抗病魔的勇敢姿态&#x…...