<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Coldin04's Blog</title><link>https://blog.cold04.com/</link><description>Recent content on Coldin04's Blog</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Sun, 24 May 2026 23:34:42 +0800</lastBuildDate><atom:link href="https://blog.cold04.com/index.xml" rel="self" type="application/rss+xml"/><item><title>借助 Karabiner，按需唤醒豆包输入法</title><link>https://blog.cold04.com/p/doubaoime_easyswitch_karabiner/</link><pubDate>Sun, 24 May 2026 23:34:42 +0800</pubDate><guid>https://blog.cold04.com/p/doubaoime_easyswitch_karabiner/</guid><description>
 &lt;blockquote&gt;
 &lt;p&gt;请注意，本文章由AI代写，语句可能存在不通顺或者啰唆等情况，我会有空时进行优化。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;今天早上装了豆包输入法。起因很简单——看了一些关于它语音后处理的讨论，好奇一个外挂了小语言模型的输入法，在语音转文字这件事上到底能做到什么程度。试了一圈下来，识别准确率和文本优化确实超出了预期。不过我没打算把它设为主力输入法。日常打字我还是习惯 Rime / 鼠须管，无论手感还是隐私考量都更顺手。所以策略很明确：&lt;strong&gt;打字归 Rime，说话归豆包。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;但问题也跟来了。豆包的语音输入只有在豆包输入法本身处于激活状态时才稳定——这意味着每次想用语音，得先手动切到豆包，用完再切回去。一次两次还好，频繁操作就很打断节奏。我需要一个更轻的方式，把&amp;quot;切换→语音→切回&amp;quot;这个流程压缩成一次操作。&lt;/p&gt;
&lt;p&gt;之前其实写过一篇关于豆包输入法整体体验的文章（《&lt;a class="link" href="https://blog.cold04.com/p/doubaoime_first_test/" target="_blank" rel="noopener"
 &gt;用嘴写 Prompt：豆包输入法如何成为我与 AI 对话的「语音中介」&lt;/a&gt;》），聊的是语音后处理的价值和工作流整合。这篇不重复那些，只聚焦一个问题：怎么用 Karabiner 把豆包当成一个&amp;quot;随叫随走&amp;quot;的语音工具。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="想清楚要做什么"&gt;想清楚要做什么
&lt;/h2&gt;&lt;p&gt;需求拆开来看其实就三步：切到豆包、触发语音、用完切回 Rime。如果再加一个约束——不引入新的常驻工具，只在已有的 Karabiner-Elements 里解决——那就变成了一个 Karabiner 规则设计问题。&lt;/p&gt;
&lt;p&gt;键位选择上没太多纠结。右 Command 平时几乎不用，不跟 Fn / Globe 的系统切换打架，也不影响我 Caps Lock 上已有的组合规则。交互逻辑也很快定下来：双击右 Command，第一次唤醒语音，第二次结束并切回。&lt;/p&gt;
&lt;p&gt;真正让我折腾了一下午的，是第二步——&amp;ldquo;触发语音&amp;quot;这四个字。&lt;/p&gt;
&lt;h2 id="右-option-双击到底谁来发"&gt;右 Option 双击，到底谁来发
&lt;/h2&gt;&lt;p&gt;豆包输入法的语音输入，默认通过双击右 Option 唤醒。问题在于，不是随便一个&amp;quot;右 Option&amp;quot;它都认。&lt;/p&gt;
&lt;p&gt;我最先用 &lt;code&gt;osascript&lt;/code&gt; 模拟 key code 61 试了一下。按键确实发出去了，但豆包毫无反应，就像什么都没收到一样。然后换成 Swift 写了个小工具，用 CGEvent 来发右 Option——这次偶尔能唤醒，但十次里大概只有三四次成功，完全不可靠。&lt;/p&gt;
&lt;p&gt;最后用 Karabiner 自己的 &lt;code&gt;to&lt;/code&gt; 规则直接发 &lt;code&gt;right_option&lt;/code&gt;，一次就通了。&lt;/p&gt;
&lt;p&gt;这个差异其实挺有意思的。&lt;code&gt;osascript&lt;/code&gt; 的 System Events、CGEvent 的底层事件、Karabiner 发出的按键——它们走的是不同的事件通道和处理层级。豆包显然在某个层面做了过滤，只认 Karabiner 那种更&amp;quot;原生&amp;quot;的按键事件。具体是内核扩展层级的问题还是输入法进程的优先级问题，我没有深挖，但结论很清楚：右 Option 双击必须由 Karabiner 直接发，不能绕道外部脚本或工具。&lt;/p&gt;
&lt;p&gt;这个发现也让后续方案简化了不少。既然按键模拟只能交给 Karabiner，那输入法切换也干脆用 Karabiner 内置的 &lt;code&gt;select_input_source&lt;/code&gt;，整条链路都在一个工具里闭环。&lt;/p&gt;
&lt;h2 id="规则是怎么搭起来的"&gt;规则是怎么搭起来的
&lt;/h2&gt;&lt;p&gt;方案的核心是两个变量：&lt;code&gt;right_command_tapped_once&lt;/code&gt; 标记右 Command 是否已经被单按过一次（用于判断是不是双击），&lt;code&gt;doubao_voice_active&lt;/code&gt; 记录当前是否在语音流程中。&lt;/p&gt;
&lt;p&gt;整个规则拆成三段。第一段处理&amp;quot;激活语音&amp;rdquo;：当系统检测到双击右 Command、且当前不在语音状态时，依次执行切到豆包、等待 300 毫秒让输入法完成切换、发送右 Option 双击唤醒语音，最后把状态变量置位。&lt;/p&gt;
&lt;p&gt;第二段处理&amp;quot;退出语音&amp;quot;：在语音状态下再次双击右 Command，先发一次右 Option 双击让豆包结束当前语音并进入文本处理，然后等 5 秒让它完成优化，最后切回 Rime 并清掉状态变量。&lt;/p&gt;
&lt;p&gt;第三段是双击识别的基础——利用 Karabiner 的 &lt;code&gt;to_if_alone&lt;/code&gt; 机制，单按右 Command 时把 &lt;code&gt;right_command_tapped_once&lt;/code&gt; 设为 1。如果用户在超时时间内再次按下右 Command，前两段规则就会根据状态变量判断该走激活还是退出。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TD
 A[双击右 Command] --&gt; B{doubao_voice_active = 1？}
 B --&gt;|否| C[select_input_source 切到豆包]
 C --&gt; D[等待 300ms]
 D --&gt; E[发送右 Option 双击]
 E --&gt; F[标记 doubao_voice_active = 1]
 B --&gt;|是| G[发送右 Option 双击]
 G --&gt; H[等待 5000ms，给豆包整理文本]
 H --&gt; I[select_input_source 切回 Rime]
 I --&gt; J[清除 doubao_voice_active]&lt;/pre&gt;&lt;p&gt;完整规则已经发布到 Karabiner-Elements 的 Complex Modifications 规则市场：&lt;a class="link" href="https://ke-complex-modifications.pqrs.org/?q=doubao#double_tap_right_command_switch_doubaoime" target="_blank" rel="noopener"
 &gt;Double tap Right Command switch DoubaoIME&lt;/a&gt;。打开链接后点击 &lt;code&gt;Import&lt;/code&gt;，按 Karabiner 的提示导入并启用即可。&lt;/p&gt;
&lt;p&gt;如果你想根据自己的习惯调整规则（例如更换触发键、修改输入法 ID 或调整等待延迟），可以在 Karabiner 导入后修改对应参数，也可以将这篇文章链接交给 AI（如 ChatGPT 或 Claude），让它参考这个逻辑为你生成定制化配置。&lt;/p&gt;
&lt;p&gt;这套规则的核心价值在于实现了一个&lt;strong&gt;全局快速唤醒的工作流&lt;/strong&gt;：无论你在哪个 App 下，只需双击右 Command 即可瞬间切到豆包并开启语音输入，说完再次双击即可自动切回主力输入法（如 Rime），将“切换→语音→切回”的繁琐操作压缩成了一个连贯的交互。&lt;/p&gt;
&lt;h2 id="两个等待各有用意"&gt;两个等待，各有用意
&lt;/h2&gt;&lt;p&gt;规则里有两处 &lt;code&gt;vk_none&lt;/code&gt; 配合 &lt;code&gt;hold_down_milliseconds&lt;/code&gt; 做的等待，一开始可能觉得多余，实际上各有各的必要。&lt;/p&gt;
&lt;p&gt;第一个 300 毫秒在切到豆包之后、发右 Option 之前。输入法切换不是瞬间完成的——如果按键发得太急，豆包还没完全激活，右 Option 事件就会被吞掉。300 毫秒是个经验值，我的机器上没出过问题。如果你的 Mac 比较老或者后台比较重，可以适当调大。&lt;/p&gt;
&lt;p&gt;第二个 5 秒在退出时。最早我试过秒切——语音结束立刻切回 Rime——结果发现豆包经常只输出了一半，文本优化根本没做完。后来改成了先等 5 秒再切，问题就消失了。这个值可以根据习惯调：通常说短句三四秒就够了，长篇大论可能需要八秒。觉得慢就调小，发现切回去还是半成品就调大，没什么神秘的地方。&lt;/p&gt;
&lt;h2 id="关于方案选型"&gt;关于方案选型
&lt;/h2&gt;&lt;p&gt;中间也纠结过要不要用 Hammerspoon。它能力确实更强，能监听按键的按下和释放事件，写一个完整的状态机完全没问题。但需求本身并不复杂——就是双击切换加两个等待——为了这个让 Hammerspoon 常驻在后台，有点杀鸡用牛刀的感觉。而且实测下来，Karabiner 直接发的 &lt;code&gt;right_option&lt;/code&gt; 是唯一能稳定唤醒豆包的方式，换成 Hammerspoon 反而可能重蹈 CGEvent 的覆辙。&lt;/p&gt;
&lt;p&gt;Shell 脚本也是类似的情况。一开始打算用 &lt;code&gt;macism&lt;/code&gt; 做输入法切换，&lt;code&gt;osascript&lt;/code&gt; 发按键，但因为右 Option 的模拟问题，这条路一开始就走不通。目前这版完全不依赖外部脚本，切换直接用 Karabiner 内置的 &lt;code&gt;select_input_source&lt;/code&gt;。如果后面发现 &lt;code&gt;select_input_source&lt;/code&gt; 在某些 macOS 版本上不稳定，也随时可以退回去调用 &lt;code&gt;shell_command&lt;/code&gt; 执行 &lt;code&gt;macism&lt;/code&gt;——但右 Option 双击一定得留在 Karabiner 这边。&lt;/p&gt;
&lt;p&gt;这个方案用了一下午，跑了十几轮语音输入，目前没出过岔子。如果你也面临类似的需求——主力输入法不想换，但偶尔想用豆包语音——可以参考这个思路。导入后的规则里把 input_source_id 改成你自己的输入法就行，等待时间按习惯微调，其他的应该都能直接用。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;本文方案由作者亲自实验，文章整理交由AI辅助完成 *&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>用嘴写 Prompt：豆包输入法如何成为我与 AI 对话的「语音中介」</title><link>https://blog.cold04.com/p/doubaoime_first_test/</link><pubDate>Sun, 24 May 2026 17:09:57 +0800</pubDate><guid>https://blog.cold04.com/p/doubaoime_first_test/</guid><description>&lt;img src="https://files.seeusercontent.com/2026/05/24/ngI2/c4d9a56.png" alt="Featured image of post 用嘴写 Prompt：豆包输入法如何成为我与 AI 对话的「语音中介」" /&gt;
 &lt;blockquote&gt;
 &lt;p&gt;请注意，本文章由AI代写，语句可能存在不通顺或者啰唆等情况，我会有空时进行优化。&lt;/p&gt;

 &lt;/blockquote&gt;

 &lt;blockquote&gt;
 &lt;p&gt;今天早上突发奇想：如果我把自己跟 AI 聊天时的输入场景，全部切换到豆包输入法的语音输入，会怎样？结果比预期的好用得多——尤其是它的自动纠错和后处理能力。于是我顺势用它来写 Prompt，一路写到了现在。这篇文章，既是评测，也是实验报告。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="引子prompt-的本质是把话说清楚"&gt;引子：Prompt 的本质，是把话说清楚
&lt;/h2&gt;&lt;p&gt;先说一个可能有点反直觉的观点：&lt;strong&gt;好的 Prompt，不是靠堆砌「扮演一个专家」「请一步步思考」这类奇技淫巧堆出来的。好的 Prompt，是把你的需求表达清楚。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路清晰的人，哪怕用最直白的语言描述需求，AI 也能准确理解。反之，思路混乱的人，套再多 Prompt 模板也救不回来。&lt;/p&gt;
&lt;p&gt;问题在于：&lt;strong&gt;把思路转化为详尽、有清晰逻辑的文字，这个过程本身就有摩擦。&lt;/strong&gt; 尤其是在灵感涌上来的时候，打字的速度远远跟不上思考的速度。你脑子里已经跑完三圈了，手还卡在第一句话的措辞上。&lt;/p&gt;
&lt;p&gt;这其实不是新问题。几年前有一款叫 &lt;strong&gt;Typeless&lt;/strong&gt; 的产品，它的核心洞察就是这个——人们需要一个能快速把思维「倾倒」出来的工具，而不是一个功能丰富的排版软件。Typeless 后来没有成为大众产品，但它埋下了一颗种子：&lt;strong&gt;输入工具的未来，不是让打字更「强大」，而是让打字这件事本身变得更「轻」。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;豆包输入法，以及最近一批新一代 AI 输入法的出现，某种程度上就是这颗种子在语音输入领域的引爆点。&lt;/p&gt;
&lt;p&gt;所以今天早上我决定做一个小实验：把跟 AI 聊天时的输入法切换到豆包，全程用语音输入 Prompt。下面是这次实验的完整记录和思考。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一我的键盘策略日常打字-vs-语音输入"&gt;一、我的键盘策略：日常打字 vs 语音输入
&lt;/h2&gt;&lt;p&gt;先交代背景。&lt;/p&gt;
&lt;p&gt;在今天之前，我的日常打字键盘随设备而变：电脑设备上用 &lt;strong&gt;Rime（中州韵）&lt;/strong&gt;，开源、可定制、隐私可控；手机上，同时使用 &lt;strong&gt;Google 键盘（Gboard）&lt;/strong&gt; 和 &lt;strong&gt;iOS 原生键盘&lt;/strong&gt;。这三者本质上是一回事——它们只是「日常打字键盘」这个角色在不同设备上的不同面孔，没有哪一块跟「AI 语音输入」扯得上关系。&lt;/p&gt;
&lt;p&gt;然后今天早上，我&lt;strong&gt;新装了豆包输入法&lt;/strong&gt;。不是因为它打字比 Rime 更好用，纯粹是想体验一下——一个外挂了小语言模型做后处理的语音输入法，到底能准到什么程度？尤其是在给 AI 写 Prompt 这个场景下，能不能用？&lt;/p&gt;
&lt;p&gt;所以现在我的键盘实际上只分两类：&lt;/p&gt;
&lt;p&gt;角色输入法场景&lt;strong&gt;日常打字&lt;/strong&gt;Rime / Gboard / iOS 原生（随设备而定）打字、密码、私密聊天、文档&lt;strong&gt;语音输入&lt;/strong&gt;豆包输入法（新装）走路、旅行、大段输出、跟 AI 快速对话&lt;/p&gt;
&lt;p&gt;简单来说：&lt;strong&gt;打字归日常键盘，说话归豆包。&lt;/strong&gt; 豆包是第一个不以「打字体验」为核心、而是以「语音后处理」为核心加入我阵容的输入法。正因为它是新装的、带着明确实验目的来的，所以我能更客观地判断：它到底解决了什么问题，以及它想要什么回报。&lt;/p&gt;
&lt;h3 id="它还不是完美的"&gt;它还不是完美的
&lt;/h3&gt;&lt;p&gt;不过诚实地说，体验了一天，也发现了几个明显的短板。&lt;/p&gt;
&lt;p&gt;首先是&lt;strong&gt;键盘打字的粘滞感&lt;/strong&gt;。如果你习惯 Rime 或 iOS 原生键盘那种干脆利落的打字手感，切换到豆包输入法时会明显感到一种迟滞——按键反馈不够跟手，快速输入时有轻微的粘滞。不是那种「完全不能用」的糟糕，但足以让你在日常打字时坚持留在日常键盘上。换句话说，豆包输入法在键盘输入体验上，目前还完全替代不了 Rime 或自带键盘。它唯一让我愿意切换过来的理由，就是语音输入。&lt;/p&gt;
&lt;p&gt;其次是&lt;strong&gt;语音识别的边界&lt;/strong&gt;。准确率整体不错，但有几个痛点：自定义词汇缺失——像「Rime 输入法」这种相对小众的专有名词，几乎每次都会被听成「Remi 输入法」，系统也没有提供便捷的自定义词库入口来纠正；中英文混说时英文单词的识别准确率明显下降；对于一些新出现的、使用频率不高的词汇，模型显然还没有覆盖到。这其实也是当前 AI 语音识别的通病——主流场景表现好，边缘场景容易翻车。&lt;/p&gt;
&lt;p&gt;还有&lt;strong&gt;输入法切换的摩擦&lt;/strong&gt;。在日常键盘和豆包之间频繁切换，操作上确实不够方便。iOS 上需要通过长按地球图标手动选择，每次切换都是一次微小的中断。这个问题不完全是豆包的锅，更多是系统层面的限制，但作为用户，体验是真实存在的。&lt;/p&gt;
&lt;p&gt;这些短板让我不会把豆包输入法设为主力键盘。但恰恰相反——正是因为它在语音后处理这个长板上做得足够好，我才会容忍这些短板继续用它。接下来的内容，就全部围绕这个长板展开。&lt;/p&gt;
&lt;h2 id="二两种场景语音输入解决的真实痛点"&gt;二、两种场景：语音输入解决的真实痛点
&lt;/h2&gt;&lt;h3 id="场景一在路上回复跨平台消息"&gt;场景一：在路上回复跨平台消息
&lt;/h3&gt;&lt;p&gt;微信自带的语音转文字其实还不错。但问题在于——我只在微信里用微信。当我在 Telegram、Discord 或者 Signal 上收到消息时，系统自带的听写就成了唯一选择。&lt;/p&gt;
&lt;p&gt;而在走路、提东西、或者单纯不想停下来打字的时候，一个能跨 App 使用的语音输入法就成了刚需。豆包输入法在这里的优势很简单：&lt;strong&gt;任何能调出键盘的地方，就能语音输入。&lt;/strong&gt; 不需要切换 App，不需要复制粘贴。&lt;/p&gt;
&lt;h3 id="场景二天马行空跟-ai-聊天时打字跟不上脑子"&gt;场景二：天马行空跟 AI 聊天时，打字跟不上脑子
&lt;/h3&gt;&lt;p&gt;这是我认为更重要的场景。&lt;/p&gt;
&lt;p&gt;不知道你有没有过这种体验：脑子里有一个模糊但有趣的想法，想丢给 AI 聊一聊。但当你坐下来打字的时候——&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;第一句写了一半，后面的思路就散了&lt;/li&gt;
&lt;li&gt;修修改改，发现十分钟过去了还没把 Prompt 发出去&lt;/li&gt;
&lt;li&gt;最糟的是，那个最初的想法在修改过程中被自己「理性化」了，失去了原本的野性&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这时候语音输入的价值就体现出来了。&lt;strong&gt;说话的速度大约是打字的 3-4 倍&lt;/strong&gt;，而且说出来的时候，思维是连续流动的，不会被单个字词的修改打断。&lt;/p&gt;
&lt;p&gt;我之前的做法是用 Apple 听写，或者直接使用 Gemini/ChatGPT App 自带的语音输入。但问题是——&lt;strong&gt;它们能听清你在说什么，却不理解你在说什么。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="三原生听写-vs-ai-输入法不是听写而是理解"&gt;三、原生听写 vs AI 输入法：不是「听写」，而是「理解」
&lt;/h2&gt;&lt;p&gt;这是整篇文章最核心的观点。&lt;/p&gt;
&lt;p&gt;Apple 的听写、Gemini 的语音输入，本质上做的是同一件事：&lt;strong&gt;忠实转录&lt;/strong&gt;。你说什么，它就记什么。听起来没错，但在实践中，问题在于：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;口语和书面语天然有差距。&lt;/strong&gt; 我们说话时会不自觉地带上「嗯」「就是」「那个那个」——忠实转录会把这些全保留下来，导致一段 Prompt 看起来像脱口秀草稿。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;同音词完全依赖声学模型。&lt;/strong&gt; 「Rime 输入法」和「Remi 输入法」，在声学层面几乎无法区分。忠实转录不会帮你纠正，而 AI 后处理可以根据上下文推断。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;人类的即兴表达是有「毛边」的。&lt;/strong&gt; 我们边说边组织语言，句子结构往往头重脚轻、前后颠倒。忠实转录保留这些毛边，AI 后处理可以帮你「熨平」。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;豆包输入法的做法不同：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;语音识别 → 小语言模型后处理 → 输出优化后的文本&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;它不只是把你说的转成字，而是&lt;strong&gt;在转录结束后，整体性地优化词句，让它读起来像「写出来的」而不是「说出来的」&lt;/strong&gt;。包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;根据上下文修复同音错别字&lt;/li&gt;
&lt;li&gt;去除口语填充词&lt;/li&gt;
&lt;li&gt;调整语序使其更符合书面表达&lt;/li&gt;
&lt;li&gt;智能断句和标点&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;换句话说，原生听写给你的是&lt;strong&gt;草稿&lt;/strong&gt;，AI 输入法给你的是&lt;strong&gt;成品&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;对于 Prompt 来说，这一点尤为重要。因为 Prompt 的质量直接决定 AI 输出的质量——一个充满口语毛边的 Prompt 和一个通顺清晰的 Prompt，可能得到完全不同的回答。你不需要学「Prompt 工程」，你只需要把话说清楚。而豆包输入法帮你做的，就是让「说出来的话」变成「写清楚的文字」。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="四从万象拼音到豆包输入法模型驱动的输入革命"&gt;四、从万象拼音到豆包输入法：模型驱动的输入革命
&lt;/h2&gt;&lt;p&gt;这里我想引入一个有趣的类比：&lt;strong&gt;Rime 的万象拼音方案。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Rime（中州韵）是一个开源输入法引擎，万象拼音是其中一个拼音输入方案。它的核心思路是什么？&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;传统拼音输入法：规则驱动（白盒）—— 手动维护词库、拼音表、纠错规则&lt;br&gt;
万象拼音：模型驱动（黑盒）—— 通过类似语言模型的方式，根据上下文预测用户下一个要打的词&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;这和豆包输入法的思路惊人地相似。两者的共同逻辑是：&lt;/p&gt;
&lt;p&gt;传统方案新方案&lt;strong&gt;拼音输入&lt;/strong&gt;规则匹配词库万象拼音：模型预测&lt;strong&gt;语音输入&lt;/strong&gt;声学模型 + 逐字转录豆包输入法：转录 + LLM 后处理&lt;/p&gt;
&lt;p&gt;这其实反映了一个更大的趋势：&lt;strong&gt;输入法的进化方向，是从「忠实记录」到「理解意图」。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当然，有人会担心黑盒模型的不可预测性。规则系统虽然僵硬，但至少你知道它什么时候会出错、为什么会出错。模型系统像一个「输入黑箱」，你不知道它会把你的「万象拼音」理解成正确的词，还是自作主张地「润色」成另一句话。&lt;/p&gt;
&lt;p&gt;但我的态度是：&lt;strong&gt;在复杂场景下，黑盒往往比白盒更有优势。&lt;/strong&gt; 白盒需要大量的人力去写规则、维护词库、穷举边界情况，而模型可以通过数据自动习得这些。尤其是在长语句输入、AI Prompt 场景下，白盒规则很难覆盖人类表达的多样性，而黑盒模型恰好擅长处理这种「模糊但合理」的映射。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="五字节的算盘语音是触达非豆包用户的暗线"&gt;五、字节的算盘：语音是触达非豆包用户的暗线
&lt;/h2&gt;&lt;p&gt;说了这么多用户体验的好话，也该聊聊「代价」。&lt;/p&gt;
&lt;p&gt;豆包输入法是免费的。字节不是慈善机构。它的商业逻辑其实很清楚：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;触达非豆包用户。&lt;/strong&gt; 像我这样的人——用 Claude、ChatGPT、Gemini，但不愿意用豆包——字节通过输入法照样能接触到我们。输入法是比 AI 助手更底层的入口，只要你在打字，你就绕不开它。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;收集 Prompt 级语料。&lt;/strong&gt; 用户通过语音输入的 Prompt、聊天内容、搜索关键词，都是极其高质量的训练数据。尤其是 Prompt——它直接反映了用户想要什么、怎么表达需求。这对于优化豆包模型本身、或者构建用户意图理解能力，都有巨大价值。即使用户用的是 Claude 而不是豆包，字节依然能通过输入法了解到「用户是怎么跟 AI 说话的」。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户画像与个性化。&lt;/strong&gt; 输入法天然能了解你的语言习惯、常用词汇、表达风格。即使用户不在字节的生态里（不用豆包、不用抖音、不用头条），输入法依然可以成为拼图的一块。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这对用户来说意味着什么？我的看法是：&lt;strong&gt;这是一笔需要「知情」的交易，而不是需要「拒绝」的交易。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;字节不是偷偷摸摸地在做这件事。输入法需要联网才能使用云端语音识别和 AI 后处理，这是功能上的必要代价——就像你用 Gboard 的语音输入，Google 也会收到你的语音数据一样。&lt;/p&gt;
&lt;p&gt;关键在于，你是否清楚自己在交换什么，以及是否有选择地控制这种交换。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="六我的选择数据分区而非数据拒绝"&gt;六、我的选择：「数据分区」而非「数据拒绝」
&lt;/h2&gt;&lt;p&gt;回到开头提到的键盘策略。&lt;/p&gt;
&lt;p&gt;我完全可以在手机上只装 Rime，所有场景都拒绝被收集数据。但我不这么做，因为我觉得&lt;strong&gt;有些场景下，语音输入的效率提升远大于数据隐私的代价&lt;/strong&gt;。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;我在走路时回复一条 Telegram 消息——这不会泄露什么惊天秘密，但停下来打字会打断我的节奏。&lt;/li&gt;
&lt;li&gt;我突然有一个天马行空的想法想和 Claude 聊聊——说五分钟的话就能产出几百字的 Prompt，这创造的价值远超字节可能从中提取的几条语料。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;而对于日常的打字——尤其是在输入密码、私人聊天、工作文档时——我切回 Rime 或 iOS 原生键盘。&lt;/p&gt;
&lt;p&gt;这就像你不会在家门口修一堵防火墙，但你会给卧室装窗帘。&lt;strong&gt;数据隐私不是非黑即白的开关，而是根据场景调节的旋钮。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="七我的写作工作流从-cyime-到豆包输入法"&gt;七、我的写作工作流：从 Cyime 到豆包输入法
&lt;/h2&gt;&lt;p&gt;聊完输入，再聊聊输出。这篇文章是怎么被「生产」出来的？我的完整工作流是这样的：&lt;/p&gt;
&lt;h3 id="1-语音倾倒--豆包输入法"&gt;1. 语音倾倒 → 豆包输入法
&lt;/h3&gt;&lt;p&gt;我先用豆包输入法的语音输入，把脑子里关于这篇文章的所有想法一股脑说出来。不需要组织语言，不需要在乎措辞——就是把思维「倾倒」出来。豆包输入法的后处理会帮我自动整理成通顺的文字。&lt;/p&gt;
&lt;p&gt;这一步解决的是「从零到草稿」的摩擦力。&lt;/p&gt;
&lt;h3 id="2-ai-辅助整理--cyime--mcp"&gt;2. AI 辅助整理 → Cyime + MCP
&lt;/h3&gt;&lt;p&gt;草稿有了之后，我把它丢到我正在用的编辑器 —— &lt;a class="link" href="https://github.com/Coldin04/Cyime" target="_blank" rel="noopener"
 &gt;Cyime(青柠写) &lt;/a&gt; 里面。&lt;/p&gt;
&lt;p&gt;当然，欢迎访问 &lt;a class="link" href="https://github.com/Coldin04/Cyime" target="_blank" rel="noopener"
 &gt;https://github.com/Coldin04/Cyime&lt;/a&gt; 了解这个项目。&lt;/p&gt;
&lt;p&gt;Cyime 是我自己用两个月时间写的一个 Web 编辑器，基于 Tiptap 构建，原生支持 Markdown 语法。它有两个我认为很实用的特性：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;图片存储的「私有一键转公开」&lt;/strong&gt;：文章里粘贴的图片默认存在 Cloudflare R2（私有云存储），安全可控。当你需要导出并发布到博客的时候，可以一键将图片批量上传到公开图床，省去了手动搬图的麻烦。换句话说，写的时候是隐私的本地工作区，发布的时候是无缝切换的公开环境。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内置 AI MCP 和 Skill 支持&lt;/strong&gt;：这是前两天刚加的新功能。Cyime 集成了 MCP（Model Context Protocol），可以直接调用 AI 来辅助写作——比如你现在正在读的这篇文章，我就是在 Cyime 里把语音转录的原始草稿交给 AI，让它帮我整理结构、展开论点、润色表达。&lt;/li&gt;
&lt;/ol&gt;

 &lt;blockquote&gt;
 &lt;p&gt;这里我想特别说明一下，避免误解：&lt;strong&gt;AI 在这里的角色是「整理者」，不是「创作者」。&lt;/strong&gt; 文章的所有观点、素材、逻辑框架和表达语气都来自我自己——AI 只是帮我省去了「把散乱的草稿组织成通顺文章」这个体力活。这和「洗稿」有本质区别：洗稿是用 AI 把他人的内容换一种说法，而我的做法是用 AI 把自己的内容整理得更清晰。创意的源头和最终审校权始终在自己手里。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="3-人工审校--导出发布"&gt;3. 人工审校 → 导出发布
&lt;/h3&gt;&lt;p&gt;AI 整理完之后，我在 Cyime 里做最后一轮修改——调整语气、补充细节、删掉 AI 产生的不准确表达。确认无误后，利用 Cyime 的导出功能，一键处理图片并发布到博客。&lt;/p&gt;
&lt;p&gt;整个流程的核心哲学是：&lt;strong&gt;把人的精力集中在「思考」和「审校」两个高价值环节，把「打字」和「排版」两个低价值环节交给工具。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;而这个流程得以跑通，豆包输入法在输入侧、Cyime 在编辑侧，各补上了一块关键的拼图。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="八声音正在成为思考的新界面"&gt;八、声音正在成为思考的新界面
&lt;/h2&gt;&lt;p&gt;最后说一点展望。&lt;/p&gt;
&lt;p&gt;过去写一篇博客，我需要在空白文档前坐很久，组织语言、斟酌词句、反复修改——大量的精力消耗在「写」这个行为本身，而不是「思考」。&lt;/p&gt;
&lt;p&gt;而今天这套工作流让我的角色发生了转变：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;豆包输入法&lt;/strong&gt; → 把声音变成草稿&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI（通过 Cyime MCP）&lt;/strong&gt; → 把草稿整理成结构化的初稿&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;我&lt;/strong&gt; → 思考和最终审校&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我发现自己从「打字员 + 编辑」变成了「思考者 + 最终审校」。而语音输入在其中扮演的角色不是「替代打字」，而是 &lt;strong&gt;「替代第一稿」&lt;/strong&gt; ——它消除了从脑海中的想法到纸面上的文字之间最痛苦的摩擦。&lt;/p&gt;
&lt;p&gt;这让我想起一个观点：&lt;strong&gt;AI 时代的核心竞争力，不是「会不会写」，而是「会不会想」。&lt;/strong&gt; 而语音输入 + AI 后处理，正在让「想」和「写」之间的距离缩短到几乎为零。&lt;/p&gt;
&lt;p&gt;豆包输入法当然不是唯一在做这件事的产品。但它目前是我体验过的、在中文长句语音输入场景下做得最好的一个。至于字节借此收集了多少数据、优化了多少模型——那是他们的事。我在知情的前提下选择使用它，因为我觉得这笔交易划算。&lt;/p&gt;
&lt;p&gt;而也许更值得关注的是：&lt;strong&gt;当声音成为思考的新界面，我们和 AI 之间的对话方式，会不会从根本上发生变化？&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;本文初稿使用豆包输入法语音输出原始想法，在 Cyime 中通过 MCP 辅助整理结构，经人工审校后完成。结论是：如果你用对了工具，往往能事半功倍的完成工作。&lt;/em&gt;&lt;/p&gt;</description></item><item><title>由JUnit单元测试实验开始，浅学 SpringBoot初始化和测试</title><link>https://blog.cold04.com/p/java-junit-first-start/</link><pubDate>Tue, 19 May 2026 22:48:20 +0800</pubDate><guid>https://blog.cold04.com/p/java-junit-first-start/</guid><description>&lt;p&gt;前两周软件测试课上，老师借由JUnit，来介绍单元测试并予以实践。之前没怎么写过Java，也正好以此机会了解一下Java的基本语法。&lt;/p&gt;
&lt;p&gt;在开始学习和实验前，我已经在电脑的本地环境中配置好JDK和基础的代码支持环境，这里就不过多赘述。&lt;/p&gt;
&lt;h2 id="基础介绍"&gt;基础介绍
&lt;/h2&gt;&lt;h3 id="什么是单元测试"&gt;什么是单元测试
&lt;/h3&gt;&lt;p&gt;单元测试是对软件中最的可测试单元（通常是一个法或类）进检查和验证的过程。在软件开发过程中，每实现个功能模块，就需要验证其是否正常作、是否达到预期效果。只有确保每个模块都正常工作，才能保证整个软件系统的平稳运行。&lt;/p&gt;
&lt;h3 id="为什么需要junit"&gt;为什么需要JUnit
&lt;/h3&gt;&lt;p&gt;在没有JUnit之前，开发者通常通过编写main方法来测试代码。例如，测试一个计算器类的加法方法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestCalculator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Calculator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 需要人工判断结果是否正确&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这种传统式存在明显弊端：需要动对比测试数据，法动化判断；当测试量很时，难以同时管理多个测试；测试代码与业务代码混在起，不利于维护。&lt;/p&gt;
&lt;p&gt;JUnit是Java领域最流的单元测试框架，它能帮助开发者简化测试流程，在编写代码的同时进单元测试，快速追踪问题原因，降低回归错误的难度。&lt;/p&gt;
&lt;p&gt;借由测试框架，对于初学者来说，也能更好的规范相关测试行为， 例如实验指导书中重点提到 &lt;code&gt;@BeforeEach&lt;/code&gt; &lt;code&gt;@BeforeAll&lt;/code&gt; &lt;code&gt;@AfterEach&lt;/code&gt; &lt;code&gt;@AfterAll&lt;/code&gt; ，在某些需要临时数据环境中，也可以方便的在单元测试或者整体的文件测试开始时添加，测试后及时清理。保证相关数据相对隔离，不会因为某些情况下忘记清理异常数据或者添加数据而导致的测试额外问题，也减轻了测试者在每次测试前后的负担。&lt;/p&gt;
&lt;h2 id="环境配置"&gt;环境配置
&lt;/h2&gt;&lt;p&gt;原实验档案建议使用IDEA创建Spring项目，方便快速配置环境、配置依赖。不过我个人认为，为了这一个简单的单元测试引入整个重型IDE，不太是我的风格，我便使用了更简单的方法完成环境的初始化。&lt;/p&gt;
&lt;p&gt;实际上&lt;code&gt;SpringBoot&lt;/code&gt; 也可以通过官方的 &lt;a class="link" href="https://start.spring.io/" target="_blank" rel="noopener"
 &gt;https://start.spring.io/&lt;/a&gt; 快速初始化，界面如下，通过相关页面，可以快速生成需要的项目脚手架，大大节省时间。&lt;/p&gt;
&lt;p&gt;&lt;img alt="图片.png" class="gallery-image" data-flex-basis="398px" data-flex-grow="166" height="1706" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://files.seeusercontent.com/2026/05/19/x7Qn/a10f44f.png" width="2836"&gt;&lt;/p&gt;
&lt;p&gt;当然，也可以使用命令行工具快速创建项目，我创建的试验项目，列表如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl https://start.aliyun.com/starter.tgz &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="nv"&gt;groupId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;com.cold04 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="nv"&gt;artifactId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;junit-lab &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="nv"&gt;dependencies&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;web &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="nv"&gt;baseDir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;junit-lab &lt;span class="p"&gt;|&lt;/span&gt; tar -xzvf -
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;创建完成后，可以看到相关文件既创建成功。接下来是完成Lab相关的习题。&lt;/p&gt;
&lt;h2 id="计数器练习"&gt;计数器练习
&lt;/h2&gt;&lt;p&gt;使用命令快速创建相关函数文件，要求的是实现一个简易计算器项目，并分别对相关函数进行测试。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p src/main/java/com/cold04/junitlab/calculator
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p src/test/java/com/cold04/junitlab/calculator
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;首先创建&lt;code&gt;Calculator.java&lt;/code&gt;文件，相关代码如下所示&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.cold04.calculator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Calculator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 加法&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 减法&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//乘法&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;multiply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//除法&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;除数不能为零&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;接下来创建测试类文件，位于 &lt;code&gt;src/test/java/com/cold04/calculator/CalculatorTest.java&lt;/code&gt; ，代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;span class="lnt"&gt;58
&lt;/span&gt;&lt;span class="lnt"&gt;59
&lt;/span&gt;&lt;span class="lnt"&gt;60
&lt;/span&gt;&lt;span class="lnt"&gt;61
&lt;/span&gt;&lt;span class="lnt"&gt;62
&lt;/span&gt;&lt;span class="lnt"&gt;63
&lt;/span&gt;&lt;span class="lnt"&gt;64
&lt;/span&gt;&lt;span class="lnt"&gt;65
&lt;/span&gt;&lt;span class="lnt"&gt;66
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.cold04.calculator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.junit.jupiter.api.*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.junit.jupiter.api.Assertions.*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CalculatorTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Calculator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@BeforeEach&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;setUP&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;初始化 Calculator 对象中&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@AfterEach&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;tearDown&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;测试方法执行完毕&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@BeforeAll&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;initAll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;所有测试方法执行前的初始化&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@AfterAll&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;tearDownAll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;所有测试方法执行后的清理&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;testAdd&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;正在测试 add 方法&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;5 + 5 应该等于 10&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;-5 + 5 应该等于 0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;正在测试 add 方法的负数情况&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;-5 + -5 应该等于 -10&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;-2 + -3 应该等于 -5&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;testSubtract&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;10 - 5 应该等于 5&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;5 - 5 应该等于 0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;testMultiply&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;5 * 5 应该等于 25&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;-5 * 3 应该等于 -15&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;testDivide&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;10 / 5 应该等于 2.0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;5 / 2 应该等于 2.5&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;testDivideByZero&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 测试除以零的情况，应该抛出 IllegalArgumentException&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertThrows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;除以零应该抛出 IllegalArgumentException&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;此时，相关主要文件已经创建完毕，且可以开始运行并测试，使用 &lt;code&gt;./mvnw -Dtest=CalculatorTest test&lt;/code&gt; 指令既可开始测试。&lt;/p&gt;
&lt;h2 id="测试和实验"&gt;测试和实验
&lt;/h2&gt;&lt;h3 id="基础测试"&gt;基础测试
&lt;/h3&gt;&lt;p&gt;如下图所示，输入 &lt;code&gt;./mvnw -Dtest=CalculatorTest test&lt;/code&gt; 后，相关提示如下，显然测试通过。&lt;/p&gt;
&lt;p&gt;&lt;img alt="图片.png" class="gallery-image" data-flex-basis="417px" data-flex-grow="173" height="1288" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://files.seeusercontent.com/2026/05/19/9ehI/8a62284.png" width="2238"&gt;&lt;/p&gt;
&lt;h3 id="修改断言测试异常提示"&gt;修改断言，测试异常提示
&lt;/h3&gt;&lt;p&gt;如下图所示，这边假&lt;code&gt;testMultiply&lt;/code&gt; 中 &lt;code&gt;-5 * 3&lt;/code&gt; 因为测试者的忽视，意外写错&lt;code&gt;-15&lt;/code&gt;，再次运行测试。如下图，可显然看到，测试在运行时指出了相关错误，但对于后续测试，是不影响的。对于测试前后的初始化调用，也不会因为某个单元测试不通过而停止。个人对此的理解是，测试前的环境准备和测试后的清理工作必不可少，例如在一些数据库环境中，在测试前写入相关mock数据，在测试后及时清理，避免数据异常影响下一阶段的测试或开发。这样的方式，显著的减少了开发时开发者的负担。&lt;/p&gt;
&lt;p&gt;&lt;img alt="图片.png" class="gallery-image" data-flex-basis="422px" data-flex-grow="176" height="1422" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://files.seeusercontent.com/2026/05/19/arB0/9ac938a.png" width="2504"&gt;&lt;/p&gt;
&lt;h3 id="测试除以零的情况"&gt;测试除以零的情况
&lt;/h3&gt;&lt;p&gt;在此情况下，我们的计算器会抛出 &lt;code&gt;IllegalArgumentException&lt;/code&gt; 错误，显然我们需要在测试中捕获这个错误。当test文件成功捕获相关异常的时候，代表相关异常处理行为正常，测试通过（此处可能略微有点反逻辑，可以理解为这个地方是能不能判断出错误的位置，判断出就予以通过）。&lt;/p&gt;
&lt;p&gt;相关代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;testDivideByZero&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 测试除以零的情况，应该抛出 IllegalArgumentException&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertThrows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;除以零应该抛出 IllegalArgumentException&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;除数不能为零&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;经过测试，显然测试成功通过。&lt;/p&gt;
&lt;p&gt;&lt;img alt="图片.png" class="gallery-image" data-flex-basis="425px" data-flex-grow="177" height="1290" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://files.seeusercontent.com/2026/05/19/7Aqu/a899f7c.png" width="2286"&gt;&lt;/p&gt;
&lt;h2 id="字符串判断测试"&gt;字符串判断测试
&lt;/h2&gt;&lt;p&gt;完成了上述测试后，既趁热打铁，做一个如下要求的程序，并完善边界测试：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;设计一个简单的字符串工具&lt;code&gt;StringUtils&lt;/code&gt;，包含以下方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;isEmpty(String str) ：判断字符串是否为空（null 或空字符串）&lt;/li&gt;
&lt;li&gt;reverse(String str) ：反转字符串&lt;/li&gt;
&lt;li&gt;concat(String str1, String str2) ：拼接两个字符串
为该类编写完整的单元测试，要求：&lt;/li&gt;
&lt;li&gt;使用 @BeforeEach 和 @AfterEach 注解&lt;/li&gt;
&lt;li&gt;至少覆盖正常情况、边界情况和异常情况&lt;/li&gt;
&lt;li&gt;使用至少 4 种不同的断言方法&lt;/li&gt;
&lt;/ol&gt;

 &lt;/blockquote&gt;
&lt;h3 id="代码准备"&gt;代码准备
&lt;/h3&gt;&lt;p&gt;简单来说，这个程序的设计思路是：先写一个简单的工具类 &lt;code&gt;StringUtils&lt;/code&gt;，把字符串相关的常用操作封装起来，然后用 JUnit 单元测试验证每个方法在不同输入下是否符合预期。代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.cold04.stringutils&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StringUtils&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;boolean&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;字符串不能为 null&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StringBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="na"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="测试设计"&gt;测试设计
&lt;/h3&gt;&lt;p&gt;测试文件 &lt;code&gt;StringUtilsTest.java&lt;/code&gt; 的设计思路是：按方法分别测试，每个方法只验证自己对应的功能，这样出错时能很快知道是哪一块有问题。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;@BeforeEach&lt;/code&gt; 用来在每个测试方法执行前重新创建一个 &lt;code&gt;StringUtils&lt;/code&gt; 对象。这样每个测试都是独立的，不会互相影响。&lt;code&gt;@AfterEach&lt;/code&gt; 用来在每个测试结束后输出提示，方便观察测试执行顺序。&lt;/p&gt;
&lt;p&gt;测试内容分成三类：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;正常情况：比如 &lt;code&gt;&amp;quot;hello&amp;quot;&lt;/code&gt; 反转成 &lt;code&gt;&amp;quot;olleh&amp;quot;&lt;/code&gt;，两个普通字符串能正常拼接。这样验证基本功能是否正确。&lt;/li&gt;
&lt;li&gt;边界情况：比如 &lt;code&gt;null&lt;/code&gt;、空字符串 &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;、单个字符 &lt;code&gt;&amp;quot;a&amp;quot;&lt;/code&gt;。这些输入比较特殊，容易出错，所以要单独测。&lt;/li&gt;
&lt;li&gt;异常情况：比如 &lt;code&gt;reverse(null)&lt;/code&gt; 应该抛出 &lt;code&gt;IllegalArgumentException&lt;/code&gt;。这样可以确认程序遇到非法输入时不是随便崩溃，而是按设计抛出指定异常。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这样设计的好处是测试比较清晰：正常功能、特殊输入、错误输入都覆盖到了，后面如果代码改坏了，也能通过测试快速发现问题。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;span class="lnt"&gt;58
&lt;/span&gt;&lt;span class="lnt"&gt;59
&lt;/span&gt;&lt;span class="lnt"&gt;60
&lt;/span&gt;&lt;span class="lnt"&gt;61
&lt;/span&gt;&lt;span class="lnt"&gt;62
&lt;/span&gt;&lt;span class="lnt"&gt;63
&lt;/span&gt;&lt;span class="lnt"&gt;64
&lt;/span&gt;&lt;span class="lnt"&gt;65
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.cold04.stringutils&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.junit.jupiter.api.AfterEach&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.junit.jupiter.api.BeforeEach&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.junit.jupiter.api.Test&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.junit.jupiter.api.Assertions.assertEquals&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.junit.jupiter.api.Assertions.assertFalse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.junit.jupiter.api.Assertions.assertThrows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.junit.jupiter.api.Assertions.assertTrue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StringUtilsTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StringUtils&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stringUtils&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@BeforeEach&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stringUtils&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StringUtils&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;初始化 StringUtils 对象&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@AfterEach&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;tearDown&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;StringUtils 测试方法执行完毕&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;testIsEmpty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 边界情况：null 和空字符串都属于“空”的特殊输入。&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stringUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;null 应该被判断为空&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stringUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;空字符串应该被判断为空&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 正常情况：有内容的字符串不应该被判断为空。&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertFalse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stringUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;非空字符串不应该被判断为空&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;testReverse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 正常情况：普通字符串应该按字符顺序反转。&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;olleh&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stringUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hello 反转后应该是 olleh&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 边界情况：单字符和空字符串反转后都应该保持原样。&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stringUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;单个字符反转后应该不变&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stringUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;空字符串反转后应该仍为空字符串&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;testReverseWithNull&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 异常情况：reverse 不接受 null，应该抛出指定异常。&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertThrows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stringUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;反转 null 应该抛出 IllegalArgumentException&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;字符串不能为 null&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;testConcat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 正常情况：两个普通字符串直接拼接。&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hello world&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stringUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hello &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;world&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;两个普通字符串应该正常拼接&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 边界情况：空字符串或 null 参与拼接时，不应该导致程序出错。&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stringUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;拼接空字符串应该保持原字符串&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;world&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stringUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;world&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;第一个参数为 null 时应按空字符串处理&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stringUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;第二个参数为 null 时应按空字符串处理&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stringUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;两个参数都为 null 时应返回空字符串&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="运行测试"&gt;运行测试
&lt;/h3&gt;&lt;p&gt;通过如下命令运行测试 &lt;code&gt;StringUtils&lt;/code&gt; 模块，下图显示，相关测试很快便通过。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./mvnw -Dtest&lt;span class="o"&gt;=&lt;/span&gt;StringUtilsTest &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;img alt="图片.png" class="gallery-image" data-flex-basis="372px" data-flex-grow="155" height="1524" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://files.seeusercontent.com/2026/05/19/b5Rs/fa6797b.png" width="2364"&gt;&lt;/p&gt;
&lt;h2 id="总结"&gt;总结
&lt;/h2&gt;&lt;p&gt;单元测试是现代软件开发中不可或缺的环节，它能在开发过程中早期发现问题、提高代码质量、减少时间，并为代码重构提供安全网。同时，相关的规范也能大大减少相关开发负担，增强系统稳定性。&lt;/p&gt;
&lt;p&gt;通过这次 JUnit 单元测试实验，我不仅对 Java 中单元测试的基本写法和测试流程有了初步了解，也借这个机会快速熟悉了 Java 项目开发中的一些基础设施。例如，我了解了 Maven 这类依赖管理工具的作用，知道了如何通过 Spring Initializr 或命令行方式快速搭建 Spring Boot 项目脚手架，并在项目结构中区分业务代码和测试代码。&lt;/p&gt;
&lt;p&gt;在单元测试方面，我学习并实践了 JUnit 中常见的测试注解和断言方法，例如 &lt;code&gt;@Test&lt;/code&gt;、&lt;code&gt;@BeforeEach&lt;/code&gt;、&lt;code&gt;@AfterEach&lt;/code&gt;、&lt;code&gt;assertEquals&lt;/code&gt;、&lt;code&gt;assertThrows&lt;/code&gt; 等。通过计算器和字符串工具类的测试，我体会到单元测试不仅可以验证正常功能，也能覆盖边界情况和异常情况，从而帮助开发者更早发现问题、降低后续维护成本。&lt;/p&gt;
&lt;p&gt;此外，由于我之前也写过 Python 中的 &lt;code&gt;pytest&lt;/code&gt; 测试，对单元测试的基本思想并不陌生，例如测试函数的组织、断言结果是否符合预期、通过异常测试验证错误处理逻辑等。因此这次学习 JUnit 时，也能将它和之前使用 &lt;code&gt;pytest&lt;/code&gt; 的经验联系起来理解。总体来看，这次实验让我对 Java 项目的搭建、依赖管理、脚手架生成以及单元测试流程都有了更完整的认识。&lt;/p&gt;</description></item><item><title>Cache 三种映射方式（直接/全相联/组相联）</title><link>https://blog.cold04.com/p/cache_mapping/</link><pubDate>Sat, 27 Dec 2025 10:00:00 +0800</pubDate><guid>https://blog.cold04.com/p/cache_mapping/</guid><description>&lt;h2 id="基础知识先把底层逻辑讲明白"&gt;基础知识（先把底层逻辑讲明白）
&lt;/h2&gt;&lt;h3 id="一从块开始cache-是什么为什么要映射"&gt;一、从“块”开始：Cache 是什么？为什么要映射？
&lt;/h3&gt;&lt;p&gt;如果你还不知道 Cache 是啥，可以把它理解成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CPU 旁边的一小块“超快内存”&lt;/strong&gt;（容量小但速度快）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;主存（内存）很大但更慢&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CPU 运行时会频繁读/写内存。为了避免每次都去“慢的主存”取数据，硬件会把&lt;strong&gt;最近用过、很可能马上还会用到&lt;/strong&gt;的数据，先放进 Cache。&lt;/p&gt;
&lt;br&gt;
&lt;h4 id="为什么-cache-不是按一个字节一个字搬运而是按块block搬运"&gt;为什么 Cache 不是“按一个字节/一个字”搬运，而是“按块（Block）”搬运？
&lt;/h4&gt;&lt;p&gt;因为程序往往有 &lt;strong&gt;局部性（Locality）&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;* **时间局部性**：刚用过的数据，可能马上还会用。
* **空间局部性**：访问了地址 A，往往很快也会访问 A 附近的地址。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以 Cache 和主存交换数据时，通常一次把&lt;strong&gt;一整段连续地址&lt;/strong&gt;搬上来，这段连续地址就叫一个 &lt;strong&gt;块（Block）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;举个最直观的例子：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;块大小 = 16B&lt;/li&gt;
&lt;li&gt;你读取地址 &lt;code&gt;0x1000&lt;/code&gt; 的 1 个字节&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;硬件往往会把 &lt;code&gt;0x1000 ~ 0x100F&lt;/code&gt; 这 16B &lt;strong&gt;整块&lt;/strong&gt;放进 Cache。
这样你接下来再访问 &lt;code&gt;0x1001&lt;/code&gt;、&lt;code&gt;0x1002&lt;/code&gt;……就很可能直接命中（hit）。&lt;/p&gt;
&lt;br&gt;
&lt;h4 id="映射mapping到底在干嘛"&gt;“映射（Mapping）”到底在干嘛？
&lt;/h4&gt;&lt;p&gt;关键矛盾只有一句：&lt;strong&gt;Cache 容量远小于主存&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;主存里有海量的块，但 Cache 里只有有限的“位置”能放块（这些位置叫 &lt;strong&gt;行 Line&lt;/strong&gt;）。于是必须规定：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;“主存的某个块，进 Cache 时允许放到哪些行（或哪些组 Set）里？”&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;这个规定就是 &lt;strong&gt;映射方式&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;不同映射方式的区别，就体现在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; - 允许放的位置越多：越不容易互相顶掉（冲突少），但查找/硬件更复杂。
 - 允许放的位置越少：查找更快/硬件更简单，但更容易冲突（两个热块老挤一个位置）。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这页只讲一件事：&lt;strong&gt;一段内存地址（或内存块）到底怎么“放进”Cache&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;br&gt;
&lt;h3 id="二一次访问到底发生什么hitmiss-机制"&gt;二、一次访问到底发生什么：Hit/Miss 机制
&lt;/h3&gt;&lt;p&gt;很多同学卡住不是因为公式，而是因为不知道“算出来的 Tag/Index 到底拿去干嘛”。下面给你一个&lt;strong&gt;能直接套题&lt;/strong&gt;的流程。&lt;/p&gt;
&lt;h4 id="cache-一行line里通常有什么"&gt;Cache 一行（Line）里通常有什么
&lt;/h4&gt;&lt;p&gt;把一行想成一个小盒子，里面至少有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Valid 位&lt;/strong&gt;：这行里有没有装过有效数据（没装过就一定 miss）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tag&lt;/strong&gt;：这行当前装的是“主存的哪一个块”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data（数据块）&lt;/strong&gt;：真正的块内容。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可能还会有（看题目/课程深度，知道即可）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dirty 位&lt;/strong&gt;：写回法（write-back）时用，表示这行数据是否被改过。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;替换信息&lt;/strong&gt;：比如 LRU 需要的“最近使用情况”。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="一次读写访问的标准流程最重要"&gt;一次读/写访问的标准流程（最重要）
&lt;/h4&gt;&lt;p&gt;不管直接映射/全相联/组相联，流程本质都一样，只是“要检查的行数”不同：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;算块地址 BlockAddr&lt;/strong&gt;：先把地址按块大小折算成“这是第几个块”。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;根据映射方式定位候选位置&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;直接映射：候选 = &lt;strong&gt;1 行&lt;/strong&gt;（算出 LineIndex）。&lt;/li&gt;
&lt;li&gt;组相联：候选 = &lt;strong&gt;1 组内的 k 行&lt;/strong&gt;（算出 SetIndex）。&lt;/li&gt;
&lt;li&gt;全相联：候选 = &lt;strong&gt;全部行&lt;/strong&gt;（没有 Index）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;命中判定（Valid + Tag 比较）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果某个候选行 &lt;code&gt;Valid=1&lt;/code&gt; 且 &lt;code&gt;Tag&lt;/code&gt; 匹配：&lt;strong&gt;Hit&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;否则：&lt;strong&gt;Miss&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hit 之后怎么取数据&lt;/strong&gt;：用 &lt;code&gt;Offset&lt;/code&gt; 在这行的 Data 里取到块内对应的字节/字。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Miss 之后会发生什么&lt;/strong&gt;（装入/替换）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从主存把“目标块”取到 Cache。&lt;/li&gt;
&lt;li&gt;若候选位置有空行：直接放进去。&lt;/li&gt;
&lt;li&gt;若没有空行：按替换策略（LRU/FIFO/随机）选一个受害者（victim）顶掉。&lt;/li&gt;
&lt;li&gt;若采用写回法且 victim 的 &lt;code&gt;Dirty=1&lt;/code&gt;：先把 victim 写回主存，再覆盖。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="一张从地址到命中缺失的流程图ascii-版"&gt;一张“从地址到命中/缺失”的流程图（ASCII 版）
&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CPU 发起一次访存（给你一个地址 Addr）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; v
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 按块大小切：BlockAddr = floor(Addr / BlockSize)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; v
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 按映射方式定位候选位置（行/组）：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 直接映射：LineIndex = BlockAddr mod NumLines
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 组相联： SetIndex = BlockAddr mod NumSets（组内 k 路都要查）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 全相联： 候选 = 全部行
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; v
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 在候选行里做命中判定：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 若存在某行：Valid=1 且 Tag 匹配 ---&amp;gt; HIT
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 否则 ---&amp;gt; MISS
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | v
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | 选空行或按替换策略挑 victim
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | (若 write-back 且 victim Dirty=1 则先写回)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | v
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | 从主存取目标块，装入 Cache
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; v v
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 用 Offset 取块内数据/完成读写 重新访问（这次通常会 hit）
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="写策略题目不考细节也能看懂"&gt;写策略（题目不考细节也能看懂）
&lt;/h4&gt;&lt;p&gt;写操作常见两对策略（题目若没说，通常只考映射/命中率，写策略可忽略）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Write-through（写直达）&lt;/strong&gt;：写 Cache 同时写主存（简单但慢）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write-back（写回）&lt;/strong&gt;：先只写 Cache，换出时再写回（快但要 Dirty 位）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write-allocate（写分配）&lt;/strong&gt;：写 miss 也把块先装入 Cache 再写（常见）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No-write-allocate&lt;/strong&gt;：写 miss 不装入 Cache，直接写主存（某些场景用）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="三术语对齐块block-行line-组set"&gt;三、术语对齐：块（Block）/ 行（Line）/ 组（Set）
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;块（Block）&lt;/strong&gt;：Cache 和主存交换数据的最小单位。题目常给“块大小 = 4 字 / 16B”等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;行（Line）&lt;/strong&gt;：Cache 里存放一个块的位置。有时也叫“Cache 块”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;组（Set）&lt;/strong&gt;：组相联里的一组“行”。例如 2 路组相联 = 每组 2 行。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你只要记住：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;直接映射&lt;/strong&gt;：每个主存块只能去 Cache 的“唯一一行”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全相联&lt;/strong&gt;：每个主存块可以去 Cache 的“任意一行”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;组相联&lt;/strong&gt;：每个主存块只能去“唯一一组”，但在组里可以去“任意一行”。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="四三种映射方式总览先建立直觉"&gt;四、三种映射方式总览（先建立直觉）
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;方式&lt;/th&gt;
					&lt;th&gt;主存块能放到哪里&lt;/th&gt;
					&lt;th style="text-align: right"&gt;查找速度&lt;/th&gt;
					&lt;th style="text-align: right"&gt;硬件成本&lt;/th&gt;
					&lt;th&gt;常见缺失类型&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;直接映射 (Direct Mapped)&lt;/td&gt;
					&lt;td&gt;固定 1 行&lt;/td&gt;
					&lt;td style="text-align: right"&gt;最快&lt;/td&gt;
					&lt;td style="text-align: right"&gt;最低&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;冲突缺失&lt;/strong&gt;明显&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;全相联 (Fully Associative)&lt;/td&gt;
					&lt;td&gt;任意行&lt;/td&gt;
					&lt;td style="text-align: right"&gt;最慢&lt;/td&gt;
					&lt;td style="text-align: right"&gt;最高&lt;/td&gt;
					&lt;td&gt;基本无冲突缺失&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;组相联 (Set Associative)&lt;/td&gt;
					&lt;td&gt;固定 1 组 + 组内任意行&lt;/td&gt;
					&lt;td style="text-align: right"&gt;居中&lt;/td&gt;
					&lt;td style="text-align: right"&gt;居中&lt;/td&gt;
					&lt;td&gt;冲突缺失缓解&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;缺失（Miss）通常分三类（考试高频）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;强制缺失&lt;/strong&gt;（Compulsory/Cold Miss）：第一次访问某块必 miss。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;容量缺失&lt;/strong&gt;（Capacity Miss）：Cache 总容量不够，装不下要用的块。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;冲突缺失&lt;/strong&gt;（Conflict Miss）：容量够，但“映射规则”把多个块挤到同一行/同一组。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="五地址怎么切tag--index--offset"&gt;五、地址怎么切：Tag / Index / Offset
&lt;/h3&gt;&lt;p&gt;题目常写：&lt;/p&gt;
$$ \text{Address} = \text{Tag} \parallel \text{Index} \parallel \text{Offset} $$&lt;p&gt;含义（按字节寻址的经典默认）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Offset（块内偏移）&lt;/strong&gt;：你要这个块里的第几个字节/字。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Index（索引）&lt;/strong&gt;：去 Cache 的哪一行（直接映射）/哪一组（组相联）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tag（标记）&lt;/strong&gt;：用来确认“这一行/这一组里装的到底是哪一个主存块”。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="三种映射方式核心"&gt;三种映射方式（核心）
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;块地址（Block Address）：&lt;/p&gt;
$$ \text{BlockAddr} = \left\lfloor \frac{\text{MemAddr}}{\text{BlockSize}} \right\rfloor $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;直接映射：&lt;/p&gt;
$$ \text{LineIndex} = \text{BlockAddr} \bmod \text{NumLines} $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;$k$ 路组相联（$k$-way）：&lt;/p&gt;
$$ \text{SetIndex} = \text{BlockAddr} \bmod \text{NumSets},\quad \text{NumSets}=\frac{\text{NumLines}}{k} $$&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;小提示：如果题目给的访问序列看起来像 &lt;code&gt;16,17,18,19 ...&lt;/code&gt; 这种“连续加 1”，很可能给的是&lt;strong&gt;字地址&lt;/strong&gt;或&lt;strong&gt;字节地址&lt;/strong&gt;；你要先用块大小把它们折算成块地址（上面的 BlockAddr）。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="一直接映射direct-mapped"&gt;一、直接映射（Direct Mapped）
&lt;/h3&gt;&lt;h4 id="规则一句话版"&gt;规则（一句话版）
&lt;/h4&gt;&lt;p&gt;每个主存块只能映射到 Cache 的&lt;strong&gt;唯一一行&lt;/strong&gt;：&lt;/p&gt;
$$ \text{LineIndex} = \text{BlockAddr} \bmod \text{NumLines} $$&lt;h4 id="做题时你在做什么"&gt;做题时你在做什么
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;先算这个访问属于哪个 &lt;strong&gt;BlockAddr&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;再用取模算出它去 &lt;strong&gt;哪一行&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;去那一行比对 &lt;strong&gt;Tag&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tag 相同：&lt;strong&gt;命中（Hit）&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Tag 不同或空：&lt;strong&gt;缺失（Miss）&lt;/strong&gt;，把新块塞进来（旧的被直接踢掉）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="直观图"&gt;直观图
&lt;/h4&gt;&lt;p&gt;&lt;img alt="Direct Mapped Cache" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.cold04.com/p/cache_mapping/Direct_Mapped_Cache.svg"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="二全相联fully-associative"&gt;二、全相联（Fully Associative）
&lt;/h3&gt;&lt;h4 id="规则一句话版-1"&gt;规则（一句话版）
&lt;/h4&gt;&lt;p&gt;主存块可以进 Cache 的&lt;strong&gt;任意一行&lt;/strong&gt;，所以 &lt;strong&gt;没有 Index&lt;/strong&gt;（或 Index 长度为 0）。&lt;/p&gt;
&lt;h4 id="做题时你需要注意什么"&gt;做题时你需要注意什么
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;命中判定：要在“所有行”里找 Tag（硬件用并行比较，题目里就理解为“全表查”）。&lt;/li&gt;
&lt;li&gt;缺失时：必须有 &lt;strong&gt;替换策略&lt;/strong&gt;（LRU/FIFO/随机）。题目不说通常默认随机或 LRU（看老师口径）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="直观图-1"&gt;直观图
&lt;/h4&gt;&lt;p&gt;&lt;img alt="Fully Associative Cache" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.cold04.com/p/cache_mapping/Fully_Associative_Cache.svg"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="三组相联set-associative"&gt;三、组相联（Set Associative）
&lt;/h3&gt;&lt;h4 id="规则一句话版-2"&gt;规则（一句话版）
&lt;/h4&gt;&lt;p&gt;主存块只能去&lt;strong&gt;唯一一组&lt;/strong&gt;，但可以放到组内&lt;strong&gt;任意一路（way）&lt;/strong&gt;：&lt;/p&gt;
$$ \text{SetIndex} = \text{BlockAddr} \bmod \text{NumSets} $$&lt;h4 id="2-路组相联你脑中应该出现的画面"&gt;2 路组相联：你脑中应该出现的画面
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;Cache 被分成很多组（Set）。&lt;/li&gt;
&lt;li&gt;每组里有 2 行（2 way）。&lt;/li&gt;
&lt;li&gt;来了一个块：先用取模找到组号；再在这组里两行都比 Tag。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="直观图-2"&gt;直观图
&lt;/h4&gt;&lt;p&gt;&lt;img alt="Set Associative Cache" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.cold04.com/p/cache_mapping/Set_Associative_Cache.svg"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="题目与练习把分数拿到手"&gt;题目与练习（把分数拿到手）
&lt;/h2&gt;&lt;h3 id="一一个极小例子把三种方式算通"&gt;一、一个极小例子把三种方式“算通”
&lt;/h3&gt;&lt;p&gt;假设（为了演示简单）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cache 一共 4 行&lt;/li&gt;
&lt;li&gt;块大小 = 1（忽略 Offset）&lt;/li&gt;
&lt;li&gt;访问的块序列：&lt;code&gt;0, 4, 0, 4&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="直接映射4-行"&gt;直接映射（4 行）
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LineIndex = BlockAddr mod 4&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;0 和 4 都映射到行 0&lt;/li&gt;
&lt;li&gt;结果：&lt;code&gt;0&lt;/code&gt; miss，&lt;code&gt;4&lt;/code&gt; miss（顶掉 0），&lt;code&gt;0&lt;/code&gt; miss（顶掉 4），&lt;code&gt;4&lt;/code&gt; miss&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全是 miss&lt;/strong&gt;：典型的冲突缺失&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="全相联4-行"&gt;全相联（4 行）
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;0、4 都能进任意行&lt;/li&gt;
&lt;li&gt;结果：&lt;code&gt;0&lt;/code&gt; miss，&lt;code&gt;4&lt;/code&gt; miss，&lt;code&gt;0&lt;/code&gt; hit，&lt;code&gt;4&lt;/code&gt; hit&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-路组相联4-行--2-组--2-路"&gt;2 路组相联（4 行 = 2 组 × 2 路）
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;NumSets=2&lt;/code&gt;，&lt;code&gt;SetIndex=BlockAddr mod 2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;0 和 4 都落到组 0，但组 0 有 2 路&lt;/li&gt;
&lt;li&gt;结果：&lt;code&gt;0&lt;/code&gt; miss，&lt;code&gt;4&lt;/code&gt; miss（组0 还装得下），&lt;code&gt;0&lt;/code&gt; hit，&lt;code&gt;4&lt;/code&gt; hit&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="二题目分析"&gt;二、题目分析
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;ul&gt;
&lt;li&gt;Cache：&lt;strong&gt;2 路组相联&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Cache 总行数：&lt;strong&gt;32 行（块）&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;块大小：&lt;strong&gt;4 字（word）&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;地址位宽：&lt;strong&gt;16 位&lt;/strong&gt;（本题命中率计算不一定用到位宽）&lt;/li&gt;
&lt;li&gt;访存序列（看起来是“字地址”）：
&lt;code&gt;16 17 18 19 144 145 146 147 252 253 465 466&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;h4 id="第一步把地址先变成块地址-blockaddr"&gt;第一步：把“地址”先变成“块地址 BlockAddr”
&lt;/h4&gt;&lt;p&gt;块大小是 4 字，所以每 4 个连续字地址属于同一个块：&lt;/p&gt;
$$ \text{BlockAddr} = \left\lfloor \frac{\text{WordAddr}}{4} \right\rfloor $$&lt;p&gt;把序列换成块地址：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;16~19&lt;/code&gt; 都在块 $\lfloor 16/4 \rfloor = 4$&lt;/li&gt;
&lt;li&gt;&lt;code&gt;144~147&lt;/code&gt; 都在块 $\lfloor 144/4 \rfloor = 36$&lt;/li&gt;
&lt;li&gt;&lt;code&gt;252~253&lt;/code&gt; 都在块 $\lfloor 252/4 \rfloor = 63$&lt;/li&gt;
&lt;li&gt;&lt;code&gt;465~466&lt;/code&gt; 都在块 $\lfloor 465/4 \rfloor = 116$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以块序列是：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;4,4,4,4, 36,36,36,36, 63,63, 116,116&lt;/code&gt;&lt;/p&gt;
&lt;h4 id="第二步算组号2-路组相联"&gt;第二步：算组号（2 路组相联）
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;总行数 32，2 路 $\Rightarrow$ 组数：&lt;/p&gt;
$$ \text{NumSets} = 32/2 = 16 $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;组号：&lt;/p&gt;
$$ \text{SetIndex} = \text{BlockAddr} \bmod 16 $$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;计算：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;块 4：$4\bmod 16=4$（组 4）&lt;/li&gt;
&lt;li&gt;块 36：$36\bmod 16=4$（组 4）&lt;/li&gt;
&lt;li&gt;块 63：$63\bmod 16=15$（组 15）&lt;/li&gt;
&lt;li&gt;块 116：$116\bmod 16=4$（组 4）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注意：&lt;strong&gt;4、36、116 三个块都挤在同一组（组 4）&lt;/strong&gt;，这就是本题的“冲突热点”。&lt;/p&gt;
&lt;h4 id="第三步按替换策略判-hitmiss假设初始-cache-为空组内-lru"&gt;第三步：按替换策略判 Hit/Miss（假设初始 Cache 为空，组内 LRU）
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;访问块 4：miss（把块 4 装入组 4）&lt;/li&gt;
&lt;li&gt;再访问块 4 三次：hit、hit、hit（同一块内连续访问，体现空间局部性）&lt;/li&gt;
&lt;li&gt;访问块 36：miss（组 4 还有空位，装入）&lt;/li&gt;
&lt;li&gt;再访问块 36 三次：hit、hit、hit&lt;/li&gt;
&lt;li&gt;访问块 63：miss（装入组 15）&lt;/li&gt;
&lt;li&gt;再访问块 63 一次：hit&lt;/li&gt;
&lt;li&gt;访问块 116：miss（组 4 满了，需要替换；LRU 会踢掉“更久没用”的块 4）&lt;/li&gt;
&lt;li&gt;再访问块 116 一次：hit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;统计：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;总访问：12 次&lt;/li&gt;
&lt;li&gt;miss：4 次（第一次见到块 4 / 36 / 63 / 116）&lt;/li&gt;
&lt;li&gt;hit：8 次&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;命中率：&lt;/p&gt;
$$ \text{HitRate} = \frac{8}{12} = \frac{2}{3} \approx 66.7\% $$&lt;h4 id="这题在考你什么"&gt;这题在考你什么
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;块大小带来的空间局部性&lt;/strong&gt;：&lt;code&gt;16~19&lt;/code&gt; 一次装块后后面 3 次都 hit。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;组相联缓解冲突&lt;/strong&gt;：虽然 4、36、116 都落同一组，但 2 路能同时容纳其中两个。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;替换策略影响细节&lt;/strong&gt;：如果后续又访问块 4，就会因为刚才被踢掉而 miss。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="三举一反一一个正例--一个反例"&gt;三、举一反一（一个正例 + 一个反例）
&lt;/h3&gt;&lt;h4 id="正例先算块地址再算组号行号"&gt;正例：先“算块地址”再“算组号/行号”
&lt;/h4&gt;&lt;p&gt;题设：块大小 4 字，访问字地址 &lt;code&gt;145&lt;/code&gt;。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;块地址：$\lfloor 145/4 \rfloor = 36$&lt;/li&gt;
&lt;li&gt;2 路组相联，32 行 $\Rightarrow$ 16 组&lt;/li&gt;
&lt;li&gt;组号：$36\bmod 16=4$&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;结论：&lt;strong&gt;它一定在组 4（组内哪一路要看替换策略与当前内容）&lt;/strong&gt;。&lt;/p&gt;
&lt;h4 id="反例把字地址当成块地址直接取模常见低级错"&gt;反例：把“字地址”当成“块地址”直接取模（常见低级错）
&lt;/h4&gt;&lt;p&gt;错误做法：直接拿 &lt;code&gt;145 mod 16 = 1&lt;/code&gt;，说它在组 1。&lt;/p&gt;
&lt;p&gt;为什么错？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;因为 Cache 映射是按“块”为单位的。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;145&lt;/code&gt; 是块内的一个字地址，它属于块 36；映射应该用 36 去取模，而不是用 145。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;</description></item><item><title>iPhone SE3 上手体验，续航和便携的碰撞</title><link>https://blog.cold04.com/p/iphone_se3_up/</link><pubDate>Sat, 06 Sep 2025 15:00:00 +0800</pubDate><guid>https://blog.cold04.com/p/iphone_se3_up/</guid><description>&lt;h2 id="前言"&gt;前言
&lt;/h2&gt;&lt;p&gt;用腻了Android手机，总想逃回苹果生态。虽然Android自由安装应用的特性异常好用，但各家品牌各自为政，所谓“碎片化”严重，有时候统一的体验反而更重要。&lt;/p&gt;
&lt;p&gt;你问为什么要选择iPhone SE3？的确，性价比对我来说是首位的，类似865的性能对我来说完全够用，毕竟我最多算轻度游戏玩家。那最劝退的呢？显然是捉襟见肘的续航了。&lt;/p&gt;
&lt;h2 id="用机偏好"&gt;用机偏好
&lt;/h2&gt;&lt;p&gt;在选择手机的时候，最重要的还是需要考虑好自己的用机需求和相关的偏好。对于我来说，很方便的就可以观察到，我在使用手机的时候，娱乐和即时通讯是耗电的大头，而其他的需求，例如扫码使用小程序，购物，生活，打车等生活服务类的应用，使用频率并不高。但如果观察存储占用，前者的占用反而并不高，反而是后者占用的存储空间更大。可以总的概括为，装80%的应用，完成20%的事。&lt;/p&gt;
&lt;h2 id="为什么选择iphone-se3"&gt;为什么选择iPhone SE3
&lt;/h2&gt;&lt;p&gt;如果你要问大部分人为什么选择，可能会告诉你：“因为便宜啊！”但对我来说。确实是这样的，但也不完全是。要便宜的话，安卓阵营的选择更多，但我更看重apple生态带来的便利体验。此外，我还有一台小米10，作为那个”装20%应用”的手机，这样一来，我只需要一台无修改的设备来完成大部分的轻度应用即可。综合来看，我在iPhone 13 mini和iPhone SE3之间犹豫了很久，最终选择了iPhone SE3。&lt;/p&gt;
&lt;h2 id="使用体验"&gt;使用体验
&lt;/h2&gt;&lt;p&gt;拿到手上的第一感觉就是轻巧，现在的手机普遍又大又重，拿起这么小的手机，一下子手部的负担小了很多。单手操作也很轻松，甚至可以用大拇指完成大部分的操作。&lt;/p&gt;
&lt;p&gt;对于这个16:9的屏幕比例，看惯了那么多全面屏，对我来说看回来也并不会觉得有什么不适应，反而觉得很舒服。但在2025年的今天，开发者在开发应用的时候可能并不会考虑16:9屏幕的显示效果，毕竟从iPhone X发布到现在已经7年过去了，16:9的屏幕比例已经很少见了。好在大部分应用都能适配，偶尔会遇到一些应用界面显示不全的情况，适配不全的情况一般来源于跨平台开发的应用，但好在于暂时没有遇到影响使用的情况。&lt;/p&gt;
&lt;p&gt;续航方面，确实是iPhone SE3的短板，毕竟电池容量摆在那里。但好在我对手机的使用并不重度，一般都能在手机电量不足时及时给手机“续命”。对于这么小的手机来说，用一个20w的充电器就足够了，充电速度也很快。&lt;/p&gt;
&lt;h2 id="拍照"&gt;拍照
&lt;/h2&gt;&lt;p&gt;虽然说SE3的摄像头并不出色，但对于拍摄文档和扫码、随手拍来说是完全够用的。对于这个摄像头，我最满意的反而是文档拍摄的清晰度。现在部分手机（如小米10）在拍摄文档的时候，边缘可能会有发虚的情况，而iPhone SE3则不会出现这种情况，拍摄的文档清晰度很高。&lt;/p&gt;
&lt;h2 id="esim"&gt;eSIM
&lt;/h2&gt;&lt;p&gt;值得一提的是，这台手机的外版是支持eSIM的，那就很方便的，可以将我用于接受验证码的eSIM放在上面，收到短信的时候可以一键填充，十分方便。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结
&lt;/h2&gt;&lt;p&gt;总的来说，iPhone SE3是一款非常适合轻度用户的手机，尤其是对于那些需要一台便携、轻巧且能够满足日常使用需求的用户来说，iPhone SE3无疑是一个不错的选择。虽然续航是它的短板，但对于我这样的使用习惯来说，完全可以接受。但如果你问我是否推荐，其实我并不会。这台手机其实只适合作为大部分人的“备用机”，甚至连备用机都不能上榜。续航是他的短板，但在其他方面，其实这是一台很均衡的，来源于旧时代的旗舰手机。即时他有现代化的A15处理器，现代化的eSIM功能，但他渐渐的也和这个时代格格不入了。&lt;/p&gt;</description></item><item><title>购入新域名，现在可以更畅快的访问我的主页!</title><link>https://blog.cold04.com/p/domain_co1d/</link><pubDate>Sun, 22 Dec 2024 14:34:48 +0000</pubDate><guid>https://blog.cold04.com/p/domain_co1d/</guid><description>&lt;p&gt;今天临时起意，遂购买&lt;code&gt;co1d.in&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;当初准备在namesilo购买，不过一比价，发现Spaceship更便宜，遂换这家服务商。&lt;/p&gt;
&lt;p&gt;因此，现已可通过:&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://co1d.in/" target="_blank" rel="noopener"
 &gt;co1d.in&lt;/a&gt; 访问我的主页&lt;br&gt;
&lt;a class="link" href="https://b.co1d.in/" target="_blank" rel="noopener"
 &gt;b.co1d.in&lt;/a&gt; 访问我的博客&lt;br&gt;
&lt;a class="link" href="https://n.co1d.in/" target="_blank" rel="noopener"
 &gt;n.co1d.in&lt;/a&gt; 访问我的笔记 &lt;br&gt;&lt;/p&gt;</description></item><item><title>Blog翻新，更优雅的界面，更舒适的工作方式</title><link>https://blog.cold04.com/p/new_blog/</link><pubDate>Mon, 29 Apr 2024 09:00:00 +0800</pubDate><guid>https://blog.cold04.com/p/new_blog/</guid><description>&lt;p&gt;前段时间正在愉快的对电脑进行维护，但一不小心手滑敲错了命令，导致我用了两年的Windows系统盘被无意清空。因为之前有备份文件的习惯，所以对我的损失并不算大。但由于Blog的源文件存储在家里的机械盘中，找回不那么方便，加上感觉之前的主题有些较旧了，索性打算好好的重建一下Blog。&lt;/p&gt;
&lt;h2 id="搜寻适合自己的静态网站生成器"&gt;搜寻适合自己的静态网站生成器
&lt;/h2&gt;&lt;p&gt;开始的时候，我仍打算使用Hexo作为博客的生成器，于是考虑搜寻一个好看且较贴切个人风格的主题。但无意中看到了 Hugo，便本着尝鲜的想法，打开的Hugo的官网进行查看。于是第一步，就开始挑选主题。说起来可能有那么些不可思议，我第一眼便相中了 &lt;a class="link" href="https://github.com/CaiJimmy/hugo-theme-stack" target="_blank" rel="noopener"
 &gt;Hugo Theme Stack&lt;/a&gt; 这个主题，设计风格简单明了，也没有多余的元素，而且更好的是，他可以直接使用 &lt;a class="link" href="https://github.com/CaiJimmy/hugo-theme-stack-starter" target="_blank" rel="noopener"
 &gt;Hugo Theme Stack Starter&lt;/a&gt; 导入自己的Github仓库，并可以借助 Github Action 进行自动编译文章。这样一来，确实可以简化不少的工作流程，方便我随时随地使用CodeSpace更新文章。就好比这篇文章，我就使用Surface远程CodeSpace进行编辑的。&lt;/p&gt;
&lt;h2 id="配置网站和熟悉逻辑"&gt;配置网站和熟悉逻辑
&lt;/h2&gt;&lt;p&gt;这部分其实没那么多好说的，我就是按照自己的风格进行调试，你可以在Github Commits里面看到我相关操作，因此没那么多可以聊的，按照帮助配置就好。&lt;/p&gt;
&lt;h2 id="迁移文章和遇到的问题"&gt;迁移文章和遇到的问题
&lt;/h2&gt;&lt;p&gt;网站按照自己的想法配置好后，就到了迁移文章的时候。前面说过，因为源文件丢失了，所以网站内容我都是直接从老Blog
复制粘贴下来的。因为前面的文章没有引用图片，所以开始并没有注意到问题，直到我开始迁移《记一次数据恢复和数据冷备份》 这篇文章的时候，才发现通过外链引用的图片居然打不开（心想，wtf，难道这个框架不支持图片的预览嘛），开始以为是配置没有开导致的，直到我开始看官方文档，直到我注意到&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WARNING
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Inserting external images is supported, but it is not recommended.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Features like image gallery and image zooming will not work with external images. Those feature needs to know the image&amp;#39;s dimensions, which is not possible with external images.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;啊？我当时注意到这个的时候还挺震惊的，因为我的习惯就是从外链引用图片，这下子确实麻烦起来了,甚至让我有了放弃使用的想法。不过好在经过简单搜索，发现了 &lt;a class="link" href="https://ghjayce.github.io/p/static-site-generator/hugo/hugo-theme-stack-gallery-study" target="_blank" rel="noopener"
 &gt;Hugo Theme Stack图库是怎么工作的？怎样才能支持外链图片？&lt;/a&gt; 这篇文章。&lt;/p&gt;
&lt;p&gt;不过即使找到了解决方案，也没法修改。显而易见的是，我的仓库里并没有&lt;code&gt;layouts&lt;/code&gt;文件夹，更别谈去修改了。我又开始打起了退堂鼓，不过之后又进行了一番搜索，发现官方的仓库中也说明了这一情况，但没说明白。通过&lt;code&gt;Hugo Modules&lt;/code&gt; 方式加载，可以通过新建这个目录，本地的文件会自动覆盖编译时加载的文件。这个设计太赞了！于是，按照解决方案修改好之后，在&lt;code&gt;config.toml&lt;/code&gt;中按照规则关闭&lt;code&gt;imageProcessing.content&lt;/code&gt;改成&lt;code&gt;false&lt;/code&gt;并添加有关项目，再次测试发现外链图片可正常查看了。&lt;/p&gt;
&lt;h2 id="hugo的优势"&gt;Hugo的优势
&lt;/h2&gt;&lt;p&gt;用一个字形容就是&amp;quot;快&amp;quot;，而且并不需要像&lt;code&gt;node.js&lt;/code&gt;那样在每次安装依赖时都弄得很复杂。这个主题支持使用Github Action编译，也使得我在每次写完之后可以只管上传就行，流程方面也能更快了。总而言之，这个工作流让我很满意。下一步来说，我应该会考虑专注于创作点优质的Blog内容，而系统化的内容仍会在 &lt;a class="link" href="https://note.cold04.com" target="_blank" rel="noopener"
 &gt;酷丁的笔记&lt;/a&gt; 中持续更新。&lt;/p&gt;</description></item><item><title>记一次数据恢复和数据冷备份</title><link>https://blog.cold04.com/p/data_cold_backup/</link><pubDate>Mon, 29 Jan 2024 09:00:00 +0800</pubDate><guid>https://blog.cold04.com/p/data_cold_backup/</guid><description>&lt;h2 id="前言"&gt;前言
&lt;/h2&gt;&lt;p&gt;最初，家里的一些老照片和老的资料是放在老电脑的硬盘中。不巧的是，老电脑的硬盘可能是被误格式化，导致资料丢失。刚放假的时候，出于想尝试的目的，以及想要找回一些资料的目的，我尝试了一下数据恢复，自此开始，我开始构建自己的资料冷备份体系。&lt;/p&gt;
&lt;p&gt;首先说明，我对资料的备份和恢复懂的并不多，这里记录的方法可能是错的或者并不是最适合你的方法，只是希望记录下来，以便以后查阅。欢迎各位大佬指正。&lt;/p&gt;
&lt;h2 id="数据恢复"&gt;数据恢复
&lt;/h2&gt;&lt;p&gt;因为数据之前有部分被覆写，加上硬盘也被重新格式化了，因此，我选择使用&lt;code&gt;DiskGenius&lt;/code&gt;恢复数据，最终，我成功找到了不少资料和一些照片。但因为数据部分被覆盖，很多照片都丢失了。由此可见，数据无价并不是闹着玩的。&lt;/p&gt;
&lt;p&gt;当时我操作的方法也很土，使用&lt;code&gt;Ventoy&lt;/code&gt;启动了我移动硬盘中的&lt;code&gt;Win to go&lt;/code&gt;系统，然后在&lt;code&gt;Win to go&lt;/code&gt;系统中安装了&lt;code&gt;DiskGenius&lt;/code&gt;，最后使用&lt;code&gt;DiskGenius&lt;/code&gt;恢复数据。这种方法的好处是不用拆机，但因为在老电脑上运行，速度显然受到了老电脑机能的限制。不过经过一个下午的时间，经过筛选后，也找到了不少资料。&lt;/p&gt;
&lt;p&gt;&lt;img alt="正在使用DiskGenius恢复数据的老电脑" class="gallery-image" data-flex-basis="426px" data-flex-grow="177" height="1080" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.cold04.com/p/data_cold_backup/diskgenius.jpg" width="1920"&gt;&lt;/p&gt;
&lt;p&gt;从DiskGenius中恢复的资料，我将其放在了移动硬盘中，但这些资料没有文件名，需要手动整理。为了不让自己太累，我直接让Copilot辅助我写了一个小程序，来用于将word文档中的标题作为文件名。这样，我就可以直接通过文件名来找到我想要的资料了。&lt;/p&gt;
&lt;p&gt;&lt;img alt="借助Copilot编写脚本" class="gallery-image" data-flex-basis="441px" data-flex-grow="183" height="2088" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.cold04.com/p/data_cold_backup/script_code.png" width="3840"&gt;&lt;/p&gt;
&lt;p&gt;同样，表格文件也借助了差不错的方法解决。自此，资料初步整理完成。&lt;/p&gt;
&lt;h2 id="冷备份老资料"&gt;冷备份老资料
&lt;/h2&gt;&lt;p&gt;显然，放在我的移动硬盘中以及电脑中也不是长久之际，我有定期清理空间的习惯。另外，移动硬盘存在丢失的风险。在网上浏览一圈之后，看到了“冷备份”这个词。由此，我开始挑选备份介质。&lt;/p&gt;
&lt;h3 id="挑选介质"&gt;挑选介质
&lt;/h3&gt;&lt;p&gt;首先必须明确一点，目前因为预算方面问题，我的预算并不太够。幸运的是，目前来说，我需要冷备份的资料并不是很多，也并不需要太大的储存空间。不过考虑到介质可能很久才打开检查一次，我根据需要选择机械硬盘。&lt;/p&gt;
&lt;p&gt;可能去看大部分博主的推荐，都会告诉你，目前4TB以下的机械硬盘都不那么推荐。不过考虑到预算和上述的实际需求，经过多方面学习，最终选择了2块全新的西数的1TB紫盘来完成我的任务。&lt;/p&gt;
&lt;p&gt;&lt;img alt="我所挑选的硬盘" class="gallery-image" data-flex-basis="179px" data-flex-grow="74" height="1707" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.cold04.com/p/data_cold_backup/wd_disk.jpg" width="1280"&gt;&lt;/p&gt;
&lt;p&gt;读取硬盘，目前我选用的是绿联的硬盘盒。建议替换自带的电源，但我目前预算不足，没有替换。&lt;/p&gt;
&lt;h3 id="拷贝资料"&gt;拷贝资料
&lt;/h3&gt;&lt;p&gt;我没有组Raid的条件，故我选择手动“镜像”两个盘的文件。我先拆封了一个盘，在电脑上整理好所有资料，使用fastcopy将资料复制到硬盘目录。使用fastcopy纯粹是因为他可以在拷贝资料的时候校验，拷贝大文件的时候也相对较快，体验较好。&lt;/p&gt;
&lt;p&gt;在弹出硬盘时，注意先在电脑上选择弹出，等待数秒保证硬盘停转和磁头归位后，关闭硬盘盒电源并拔出硬盘。这样做，一方面可以防止硬盘还在读写，另一方面，磁头离开硬盘盘面后，可以防止移动时磁头划伤硬盘，变成“唱片机”。&lt;/p&gt;
&lt;h3 id="定期查看和写入资料"&gt;定期查看和写入资料
&lt;/h3&gt;&lt;p&gt;一般来说，每个阶段之后，都需要将一些资料进行备份。我建议周期是半年到一年定期检查下。当然，有重要资料的时候，也别忘记写入，时间有限的话，也可以一同检查下硬盘的smart值。&lt;/p&gt;
&lt;p&gt;对于用于备份的机械硬盘来说，smart值还挺重要的，有时候smart出现警告后，要及时考虑转移资料和选择新硬盘进行备份。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结
&lt;/h2&gt;&lt;p&gt;对于每个人来说，都有或多或少的重要资料。永远要记住：“数据无价”。定期做好数据备份是一项不错的选择，不要等到失去了再追悔莫及。&lt;/p&gt;
&lt;p&gt;这里有个小插曲，我在3月份的时候，无意中格式化了Windows系统盘。因为备份习惯，导致我的资料和进度丢失并不算太多，所以还是那句话，数据无价，勤备份才是王。&lt;/p&gt;</description></item><item><title>解决mysql_secure_installation ERROR 2002</title><link>https://blog.cold04.com/p/mysql_error_2002/</link><pubDate>Tue, 21 Nov 2023 21:00:00 +0800</pubDate><guid>https://blog.cold04.com/p/mysql_error_2002/</guid><description>&lt;h2 id="问题描述"&gt;问题描述
&lt;/h2&gt;&lt;p&gt;在使用mysql_secure_installation命令时，出现以下错误：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt; &lt;span class="mi"&gt;2002&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HY000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;Can&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;t connect to local MySQL server through socket &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; (2 &amp;#34;No such file or directory&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="问题分析"&gt;问题分析
&lt;/h2&gt;&lt;p&gt;显而易见的是，1mysql_secure_installation1命令无法连接到本地的MySQL服务，原因是MySQL服务没有启动。&lt;/p&gt;
&lt;p&gt;但在之前的操作步骤中，已经使用了&lt;code&gt;systemctl start mariadb&lt;/code&gt;命令启动了MySQL服务，为什么还是无法连接呢？&lt;/p&gt;
&lt;p&gt;进入目录查看可知，在此目录下无&lt;code&gt;/var/lib/mysql/mysql.sock&lt;/code&gt;文件。&lt;/p&gt;
&lt;p&gt;使用&lt;code&gt; find / -name 'mysql.sock'&lt;/code&gt; 命令查找，发现文件在&lt;code&gt;/tmp/mysql.sock&lt;/code&gt;（部分在&lt;code&gt;/tmp/sys…/tmp/mysql.sock&lt;/code&gt; 之下）。&lt;/p&gt;
&lt;h2 id="解决方法"&gt;解决方法
&lt;/h2&gt;&lt;p&gt;先使用 &lt;code&gt;find / -name 'mysql.sock'&lt;/code&gt; 命令查找mysql.sock文件，找到文件所在目录。&lt;/p&gt;
&lt;p&gt;复制这个目录，为其创建软链接，如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ln&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.../&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="err"&gt;（这里写的是你复制的目录）&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;再次尝试使用&lt;code&gt;mysql_secure_installation&lt;/code&gt;命令，问题解决。&lt;/p&gt;
&lt;h2 id="多说两句"&gt;多说两句
&lt;/h2&gt;&lt;p&gt;其实，在新版的Mysql/MariaDB中，修改密码的方式有所变更，使用mysql_secure_installation命令修改密码的方式已经不再适用。&lt;a class="link" href="https://blog.xzr.moe/archives/4/" target="_blank" rel="noopener"
 &gt;具体可以看这里&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;新版初始化可以考虑手动初始化:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql(如果之前有密码则加上有关内容)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ALTER USER &amp;#39;root&amp;#39;@&amp;#39;localhost&amp;#39; IDENTIFIED BY &amp;#39;新密码&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;flush privileges;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;exit;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>配置ProxyChains，使得终端可以使用代理</title><link>https://blog.cold04.com/p/proxychains/</link><pubDate>Mon, 30 Oct 2023 22:00:00 +0800</pubDate><guid>https://blog.cold04.com/p/proxychains/</guid><description>&lt;p&gt;兄弟这两天忽然找我，他们实验室服务器因为配置原因，无法直接访问外网，但是他们需要下载一些东西，于是就想到了使用代理。因为一台机器中存在多个用户，自然不能在系统中直接配置代理，经过一翻查找，就想到了使用proxychains。&lt;/p&gt;
&lt;h1 id="基本环境"&gt;基本环境
&lt;/h1&gt;&lt;p&gt;简介也说明了，因为实验室的服务器提供给多人使用，部分用户是没有管理员权限的（避免因此造成不必要的麻烦），所以不能在系统中直接配置代理，这样一方面是对路由资源会造成损耗，另一方面，也不太方便在代理和直连之间切换。所以，使用proxychains是一个不错的选择。&lt;/p&gt;
&lt;h1 id="安装proxychains"&gt;安装proxychains
&lt;/h1&gt;&lt;p&gt;因为实验室服务器使用的是Debian，所以使用apt安装即可。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install proxychains
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h1 id="配置proxychains"&gt;配置proxychains
&lt;/h1&gt;&lt;p&gt;一般来说，proxychains的配置文件在/etc/proxychains.conf，但是我们强调，因为上述特殊环境，我们需要在不同用户下使用不同的配置，所以我们需要在用户目录下创建配置文件，这样就可以实现不同用户使用不同的配置。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vim ~/.proxychains/proxychains.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在这个配置文件中，我们需添加以下内容:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[ProxyList]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;socks5 127.0.0.1 1080 username password
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;其中，username和password是你的代理服务器的用户名和密码，如果没有，可以不填写。服务器地址和端口可按照需求修改。&lt;/p&gt;
&lt;h1 id="使用proxychains"&gt;使用proxychains
&lt;/h1&gt;&lt;p&gt;使用proxychains很简单，只需要在命令前加上proxychains即可，例如:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;proxychains git clone https://github.com/Coldin04/NoteShare.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;或者，也有另外一种方式：&lt;code&gt;proxychains bash&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这样，就可以在一个新的bash中使用代理了。&lt;/p&gt;
&lt;h1 id="测试连通性"&gt;测试连通性：
&lt;/h1&gt;&lt;p&gt;注意：如果使用的是socks5代理，因为socks5代理处于第五层，所以ping命令是无法使用的，只能使用curl或者wget等命令。
&lt;code&gt;proxychains curl cip.cc&lt;/code&gt;&lt;/p&gt;
&lt;h1 id="参考资料"&gt;参考资料
&lt;/h1&gt;&lt;p&gt;&lt;a class="link" href="https://github.com/haad/proxychains" target="_blank" rel="noopener"
 &gt;[1] proxychains-ng&lt;/a&gt; &lt;br&gt;
&lt;a class="link" href="https://github.com/haad/proxychains" target="_blank" rel="noopener"
 &gt;[2] Linux 配置 ProxyChains 本地代理&lt;/a&gt;&lt;/p&gt;</description></item><item><title>新站上线！用Vuepress搭建的个人笔记库</title><link>https://blog.cold04.com/p/note-news/</link><pubDate>Mon, 30 Oct 2023 22:00:00 +0800</pubDate><guid>https://blog.cold04.com/p/note-news/</guid><description>&lt;p&gt;自从转到计算机专业之后，因为很多命令在电脑上执行，故开始尝试使用了Obsidian记录笔记。一个学期下来，也攒了不少内容。本着分享的精神，我最初的想法是将Obsidian仓库发布，也方便对笔记进行备份。后来发现，Obsidian的第三方发布服务均有一定的缺陷，而官方发布服务又需要付费，价格又不太理想，很长一段时间都放弃去做这个事情了。&lt;/p&gt;
&lt;p&gt;后来，在看到一些文档的的时候，发现了很多人都使用这一套“风格”进行搭建，如&lt;a class="link" href="https://xiaolincoding.com/" target="_blank" rel="noopener"
 &gt;小林Coding&lt;/a&gt; 、&lt;a class="link" href="https://xiaolincoding.com/" target="_blank" rel="noopener"
 &gt;ArchLinux简明指南&lt;/a&gt; 等。发现均以Vuepress为基础进行搭建，于是我也开始尝试使用Vuepress搭建自己的笔记库。（其实之前考虑过Notion等工具，但后来放弃）&lt;/p&gt;
&lt;h2 id="vuepress"&gt;Vuepress
&lt;/h2&gt;&lt;p&gt;VuePress 由两部分组成：第一部分是一个极简静态网站生成器 (opens new window)，它包含由 Vue 驱动的主题系统和插件 API，另一个部分是为书写技术文档而优化的默认主题，它的诞生初衷是为了支持 Vue 及其子项目的文档需求。&lt;/p&gt;
&lt;p&gt;更多可以看&lt;a class="link" href="https://vuepress.vuejs.org/zh/" target="_blank" rel="noopener"
 &gt;官方文档&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="搭建过程"&gt;搭建过程
&lt;/h2&gt;&lt;h3 id="小插曲"&gt;小插曲
&lt;/h3&gt;&lt;p&gt;其实，Vuepress的安装非常简单，只需要使用yarn即可:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir vuepress-starter &amp;amp;&amp;amp; cd vuepress-starter
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yarn init
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yarn add -D vuepress
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;当然，也别急着就开始了，想让网站更丰富，可以考虑安装第三方的主题。当然，如果想要了解更多安装和配置的细节，也可以进入&lt;a class="link" href="https://vuepress.vuejs.org/zh/guide/getting-started.html" target="_blank" rel="noopener"
 &gt;官方文档&lt;/a&gt; 了解更多细节。&lt;/p&gt;
&lt;p&gt;我使用的是&lt;a class="link" href="https://theme-hope.vuejs.press/zh/" target="_blank" rel="noopener"
 &gt;vuepress-theme-hope&lt;/a&gt; 这个主题，这个主题主题很大程度上继承了 VuePress 默认主题的配置，并在此基础上添加了大量功能与布局优化。而且，这个主题也有blog功能，有兴趣的话可以了解一下。&lt;/p&gt;
&lt;p&gt;标题说这是小插曲，那也就顺便聊聊。当时我拿到手，也是一股脑的按照上面的步骤安装了&lt;code&gt;Vuepress&lt;/code&gt;，顺便熟悉了一下基本配置。我有个小习惯，当我正在研究的或者正在学习的东西（前提是感兴趣），我会去B站搜索看看别人的视频，或者去搜索引擎上以这个名称为关键词看看别人的配置过程这样的。无意就发现了&lt;code&gt;Vuepress-theme-hope&lt;/code&gt;和&lt;code&gt;Vuepress-theme-repo&lt;/code&gt;这两个主题。&lt;/p&gt;
&lt;p&gt;当我点开了这两者的搜索条目，才发现这两个主题并非像Wordpress或者Hexo那样导入进去，或者放入一个文件夹就能用，而是单独通过包管理器（pnpm或yarn）进行新建。后来，我含泪去转移了已经整理完成的笔记，不过这些的工作量也并不大就是。&lt;/p&gt;
&lt;h2 id="正式开始"&gt;正式开始
&lt;/h2&gt;&lt;h3 id="安装"&gt;安装
&lt;/h3&gt;&lt;p&gt;建议参考：&lt;a class="link" href="https://theme-hope.vuejs.press/zh/get-started/" target="_blank" rel="noopener"
 &gt;小白教程&lt;/a&gt;
首先，保证安装了Node.js、yarn\Pnpm和VS Code（或其他编辑器），然后根据提示安装即可。&lt;/p&gt;
&lt;p&gt;但我既然在这里提到这件事，说明我也遇到了一些问题，这里也顺便记录一下。&lt;/p&gt;
&lt;p&gt;在运行时，我首先遇到了这样的错误：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ERR_MODULE_NOT_FOUND&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Cannot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nx"&gt;katex&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;imported&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;coldin04&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;Documents&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;webnote&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;node_modules&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;mdit&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;katex&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mjs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;NodeError&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;406&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;......&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这个错误的原因是因为&lt;code&gt;vuepress-theme-hope&lt;/code&gt;的依赖包&lt;code&gt;katex&lt;/code&gt;没有找到，查询后发现，可通过:&lt;code&gt;yarn add katex&lt;/code&gt;解决。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;tips:&lt;br&gt;之后查询到，这个依赖包是用于数学公式的，如果不需要，可以不安装，去配置中将其注释掉即可。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;然后，我又遇到了这样的错误：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Error: Cannot find module &amp;#39;reveal.js/dist/reveal.css&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Require stack:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- /home/coldin04/Documents/xxx/@mr-hope/vuepress-plugin-pwa/lib/client.js
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; .....
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这个错误的原因是因为&lt;code&gt;vuepress-theme-hope&lt;/code&gt;的依赖包&lt;code&gt;reveal.js&lt;/code&gt;没有找到，查询后发现，可通过:&lt;code&gt;yarn add reveal.js&lt;/code&gt;解决。&lt;/p&gt;
&lt;p&gt;此时，如果执行&lt;code&gt;yarn dev&lt;/code&gt;，若能够正常运行，则即可进行下一步进行仔细的配置了。当然，如果还有别的运行问题，也可以借助搜索引擎或类似于ChatGPT语言大模型进行解决。&lt;/p&gt;
&lt;h3 id="配置"&gt;配置
&lt;/h3&gt;&lt;p&gt;因为Vuepress也配置过好几天了，具体也无法记的很详细了，这里就简单的说一下。当然，每个人的风格不同，配置是自然不同的，我的操作更多的是提供思路，请不要被我的步骤局限住了。&lt;/p&gt;
&lt;h4 id="base"&gt;base
&lt;/h4&gt;&lt;p&gt;首当其冲的是配置这个选项，可参考&lt;a class="link" href="https://vuejs.press/zh/reference/config.html#base" target="_blank" rel="noopener"
 &gt;Base&lt;/a&gt;。这个选项是用于设置网站的基础路径，如果你准备发布到 &lt;code&gt;https://.github.io//&lt;/code&gt; ，也就是说你的仓库地址是 &lt;code&gt;https://github.com//&lt;/code&gt; ，则将 base 设置为 “//“。&lt;/p&gt;
&lt;h4 id="导航栏"&gt;导航栏
&lt;/h4&gt;&lt;p&gt;这个选项是用于设置导航栏的.&lt;/p&gt;
&lt;p&gt;显而易见的是，我的导航栏并没有什么特殊的设置，只是简单把写过的笔记进行分类整理，然后放在了导航栏中。&lt;/p&gt;
&lt;h4 id="侧边栏"&gt;侧边栏
&lt;/h4&gt;&lt;p&gt;对于侧边栏，我是选择了通过文件结构生成，毕竟因为是笔记站，这样配置起来，可以更方便的去查找笔记。不过随着之后内容的增多，也可能会考虑对不同笔记目录单独生成不同的侧边栏。&lt;/p&gt;
&lt;h4 id="评论"&gt;评论
&lt;/h4&gt;&lt;p&gt;&lt;del&gt;主要是因为懒&lt;/del&gt; ，我选择直接将相关配置注释，关闭评论区，之后可能会考虑使用第三方评论系统。&lt;/p&gt;
&lt;h4 id="seo"&gt;SEO
&lt;/h4&gt;&lt;p&gt;这个主题的一大优点，便是自带SEO功能，且默认是开启的，可参考SEO。&lt;/p&gt;
&lt;p&gt;对于其他功能，我也并没有去仔细关注，毕竟这个主题的配置项还是很多的，而且也不是每个人都需要的，对于笔记站来说，我觉得这些功能也并不是很重要，在之后的使用中，如果有需要，再去配置也不迟。&lt;/p&gt;
&lt;h2 id="结语"&gt;结语
&lt;/h2&gt;&lt;p&gt;这个笔记站的搭建，也是我第一次使用Vuepress，也是第一次使用Vue，所以在搭建过程中，也遇到了很多问题，也是在解决问题的过程中，学习了很多知识。在这里，也希望能够帮助到其他人，也希望能够帮助到自己。&lt;/p&gt;
&lt;p&gt;在这次的配置过程中，确实让我整个人都得到了一个放松。前段时间状态确实不太行。在这次配置的过程中不断面对问题，解决问题，让我感到了久违的满足感和获得感。也让我重新找回了学习的乐趣。&lt;/p&gt;
&lt;p&gt;感谢vuepress、vuepress-theme-hope等开源项目的开发者，感谢他们的付出，让我能够使用这么好的工具。最后，也感谢你能够看到这里，希望你能够喜欢这个笔记站。&lt;/p&gt;</description></item></channel></rss>