<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>lllirunze</title><description>blog</description><link>https://lllirunze.cn/</link><language>zh_CN</language><item><title>Android Permission</title><link>https://lllirunze.cn/posts/android-permission/</link><guid isPermaLink="true">https://lllirunze.cn/posts/android-permission/</guid><description>不要对系统行为做任何假设。</description><pubDate>Fri, 06 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;最近在忙着进行新产品功能的冲刺，傻逼测试为了讨好领导，打着为使用者体验好的旗号一直提出一些正常人类根本不会执行出来的问题来给我们这帮开发提单子。其中有一个最傻逼的单子，它的内容是这样的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;当 APP 在运行过程中，临时进入后台修改应用权限，例如关闭位置权限，会导致软件重启。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;测试执拗的认为这是一个崩溃问题。这个傻逼单子让我们一堆开发围着这个问题看了一整天，最后一个大佬从&lt;strong&gt;安卓开发者文档&lt;/strong&gt;才得出结论：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;为了让系统取消应用对权限的访问权限，必须终止与应用关联的所有进程。当您调用该 API 时，系统会确定何时可以安全终止这些进程。通常，系统会等待应用有较长时间在后台运行，而不是在前台运行时。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;也就是说，任何一个安卓APP在后台修改应用权限都会导致应用重启，tb，zfb，dy等应用都是如此，这才让我们解决这个问题。（虽然这本来就不是问题）&lt;/p&gt;
&lt;p&gt;希望测试体谅一下开发，保持最起码的专业能力，不要提出傻逼问题。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;:::note[Reference]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.android.com/training/permissions/requesting?hl=zh-cn&quot;&gt;请求运行时权限&lt;/a&gt;
:::&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Linux Command Cheatsheet-1</title><link>https://lllirunze.cn/posts/linux-command-cheatsheet-1/</link><guid isPermaLink="true">https://lllirunze.cn/posts/linux-command-cheatsheet-1/</guid><pubDate>Fri, 24 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Linux命令&lt;/strong&gt;是用于与Linux操作系统进行交互的指令，通常通过终端或命令行界面输入。这些命令可以用于执行各种任务，如文件管理、系统监控、用户管理、程序执行等。每个命令通常有一个特定的功能，并且可以带有选项或参数来改变命令的行为。&lt;/p&gt;
&lt;h2&gt;Linux目录结构&lt;/h2&gt;
&lt;p&gt;linux目录是以树状管理的，我们可以输入&lt;code&gt;ls /&lt;/code&gt;获得根目录内容。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&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;&lt;code&gt;bin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;存放基本的系统命令和二进制可执行文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;boot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;包含启动系统所需的文件，例如Linux内核文件和启动加载器相关文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;存储设备文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;etc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;存放系统配置文件和管理文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;home&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;存储普通用户的个人目录&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lib&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;存放系统和应用程序所需的共享库文件。这些库文件包含程序运行所需的函数和资源。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;media&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;用于挂载可移动媒体设备（如USB驱动器、CD/DVD等）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mnt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;也是一个用于挂载临时文件系统的目录，通常用于挂载网络文件系统或其他临时设备。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;opt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;存放第三方应用程序和软件包的目录&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;包含了关于系统内核、进程、硬件等的虚拟文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;root&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;超级用户（root）的个人目录，类似于 &lt;code&gt;/home&lt;/code&gt; 目录下普通用户的目录。这个目录通常只由超级用户访问。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sbin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;存放系统管理员使用的二进制可执行文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;usr&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;存放系统用户程序、共享库、文档和其他资源，包括应用程序、开发工具、文档等内容&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;终端颜色含义&lt;/h2&gt;
&lt;p&gt;当我们进行&lt;code&gt;ls&lt;/code&gt;操作时候，会看到不同的文件(夹)的颜色不同，不同颜色具有不同含义：&lt;/p&gt;
&lt;ul&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;li&gt;红色：压缩包&lt;/li&gt;
&lt;li&gt;黄色：设备文件&lt;/li&gt;
&lt;li&gt;灰色：其他文件&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Linux终端常用快捷键&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;ctrl+b：保证不撤回字符的情况下，向左移动一个光标&lt;/li&gt;
&lt;li&gt;ctrl+f：向右移动一个光标&lt;/li&gt;
&lt;li&gt;ctrl+a：光标移动至行首&lt;/li&gt;
&lt;li&gt;ctrl+e：光标移动到行尾&lt;/li&gt;
&lt;li&gt;ctrl+d：移除光标后面第一个字符&lt;/li&gt;
&lt;li&gt;ctrl+u：删除光标之前的所有字符（不包含光标所在字符）&lt;/li&gt;
&lt;li&gt;ctrl+k：删除光标之后的所有字符（包含光标所在字符）&lt;/li&gt;
&lt;li&gt;ctrl+w：删除光标所在的整个单词&lt;/li&gt;
&lt;li&gt;ctrl+y：恢复之前一个删除的内容（撤销）&lt;/li&gt;
&lt;li&gt;双击tab：列出所有以当前输入内容作为前缀的命令/文件(夹)全称&lt;/li&gt;
&lt;li&gt;单击tab：补全命令/文件(夹)内容（如果你输入的命令为正确）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;文件权限&lt;/h2&gt;
&lt;p&gt;通过&lt;code&gt;ls la&lt;/code&gt;命令，我们可以看到每一行对应一个文件(夹)，但是前面第一列有一些&lt;code&gt;d, r, w, x, -&lt;/code&gt;之类的内容，这些被称为权限。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;r&lt;/code&gt;：可读&lt;/li&gt;
&lt;li&gt;&lt;code&gt;w&lt;/code&gt;：可写&lt;/li&gt;
&lt;li&gt;&lt;code&gt;x&lt;/code&gt;：可执行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-&lt;/code&gt;：无权限&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们可以看到，每个文件的前面包含总共10个字符，一般来说，第2-4位代表用户权限，第5-7位代表组权限，第8-10位代表其他权限。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/images/posts/linux/Snipaste_2025-02-14_23-21-24.png&quot; alt=&quot;linux premission&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;通配符&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*&lt;/code&gt;：匹配0个或者多个字符串&lt;/li&gt;
&lt;li&gt;&lt;code&gt;?&lt;/code&gt;：匹配1个字符&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[abcd]&lt;/code&gt;：匹配方括号内（a, b, c, d）内任意一个字符&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[a-z]&lt;/code&gt;：匹配a-z范围内的任意一个字符&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[!abc]&lt;/code&gt;：不匹配方括号里的任意一个字符，与&lt;code&gt;[^abc]&lt;/code&gt;一致&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;帮助命令&lt;/h2&gt;
&lt;h3&gt;&lt;code&gt;man&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;man&lt;/code&gt;是一个非常有用的命令，用于查看各种命令的&lt;a href=&quot;https://man7.org/linux/man-pages/&quot;&gt;手册页面（manual pages）&lt;/a&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;man &amp;lt;command&amp;gt;           # 查看命令的手册页
man &amp;lt;section&amp;gt; &amp;lt;command&amp;gt; # 查看特定章节的手册页
man -f &amp;lt;command&amp;gt;        # 显示给定关键字的简短信息
man -k &amp;lt;command&amp;gt;        # 根据关键词搜索帮助手册
man -w &amp;lt;command&amp;gt;        # 显示手册文件所在位置
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;{% note green fa-circle-info %}良好的英文是必备的。{% endnote %}&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;info&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;info&lt;/code&gt;命令是另一个用于查看Linux命令和工具文档的命令，与&lt;code&gt;man&lt;/code&gt;命令类似，但它提供了更详细和结构化的帮助信息。&lt;code&gt;info&lt;/code&gt;命令可以提供比&lt;code&gt;man&lt;/code&gt;更丰富的内容，包括更全面的选项和说明，并且通常具有超链接式的导航功能。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;info &amp;lt;command&amp;gt; # 查看命令的详细帮助信息
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;whatis&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;whatis&lt;/code&gt;命令是一个用于显示命令简短描述的工具，它可以快速告诉你一个命令或程序的基本功能。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;whatis &amp;lt;command&amp;gt; # 查看命令的简短描述
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;文档操作命令&lt;/h2&gt;
&lt;h3&gt;&lt;code&gt;touch&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;touch&lt;/code&gt; 命令主要用于更改文件的时间戳（修改时间和访问时间）或者创建空文件。它不会修改文件的内容，只会影响文件的时间属性。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;touch &amp;lt;file&amp;gt;             # 如果文件不存在，创建空文件；如果存在，更新文件的时间戳
touch -t &amp;lt;time&amp;gt; &amp;lt;file&amp;gt;   # 设置特定时间戳
touch -a &amp;lt;file&amp;gt;          # 只更新文件的访问时间(atime)
touch -m &amp;lt;file&amp;gt;          # 只更新文件的修改时间(mtime)
touch -r &amp;lt;file1&amp;gt; &amp;lt;file2&amp;gt; # 将file2的时间戳与file1的时间戳相同
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;mkdir&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;mkdir&lt;/code&gt;命令主要用于创建新目录。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir &amp;lt;dir&amp;gt;                  # 创建一个目录
mkdir -p &amp;lt;dir1/dir2/xxx/xxx&amp;gt; # 创建递归目录
mkdir -m &amp;lt;permission&amp;gt; &amp;lt;dir&amp;gt;  # 设置新目录的权限，默认775
mkdir -v &amp;lt;dir&amp;gt;               # 创建目录的时候显示详细信息
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;rm&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;rm&lt;/code&gt;命令是用于删除文件或目录的命令。&lt;/p&gt;
&lt;p&gt;{% note red fa-triangle-exclamation %}一般来说删除的文件和目录是不可恢复的，因此在使用 &lt;code&gt;rm&lt;/code&gt; 命令时需要小心。{% endnote %}&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rm &amp;lt;file&amp;gt;    # 删除一个文件
rm -r &amp;lt;dir&amp;gt;  # 删除目录以及里面的所有内容
rm -rf &amp;lt;dir&amp;gt; # 递归并强制删除目录
rm -i &amp;lt;dir&amp;gt;  # 删除时提示确认
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;rmdir&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;rmdir&lt;/code&gt; 命令用于删除空目录。它与 &lt;code&gt;rm&lt;/code&gt; 命令类似，但只适用于删除空目录，而不能删除包含文件或子目录的目录。使用 &lt;code&gt;rmdir&lt;/code&gt; 删除目录时，如果目录中包含任何内容，命令会失败并显示错误信息。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rmdir &amp;lt;dir&amp;gt; # 删除空目录
rmdir -p &amp;lt;dir1/dir2/dir3&amp;gt; # 删除目录及其所有空父目录
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;mv&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;mv&lt;/code&gt;命令是用于移动文件或目录的命令，它也可以用来重命名文件或目录。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mv &amp;lt;file|dir1&amp;gt; &amp;lt;dir2&amp;gt;    # 移动文件或目录到目录
mv &amp;lt;oldfname&amp;gt; &amp;lt;newfname&amp;gt; # 重命名文件或目录
mv -f &amp;lt;file&amp;gt; &amp;lt;dir&amp;gt;       # 强制覆盖文件
mv -i &amp;lt;file&amp;gt; &amp;lt;dir&amp;gt;       # 在覆盖文件时提示确认
mv -v &amp;lt;file&amp;gt; &amp;lt;dir&amp;gt;       # 显示详细信息
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;cp&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;cp&lt;/code&gt;是用于将文件或目录从一个位置复制到另一个位置。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cp &amp;lt;file&amp;gt; &amp;lt;dir&amp;gt;     # 复制文件
cp -r &amp;lt;dir1&amp;gt; &amp;lt;dir2&amp;gt; # 递归复制目录
cp -i &amp;lt;file&amp;gt; &amp;lt;dir&amp;gt;  # 提示覆盖文件
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;cd&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;cd&lt;/code&gt; 是Linux中用于切换当前工作目录的命令，是文件系统操作中最常用的命令之一。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd &amp;lt;dir&amp;gt;  # 切换到目标目录（可以是绝对路径或相对路径）
cd        # 切换到主目录
cd /      # 切换到根目录
cd ..     # 切换到上一级目录
cd .      # 在当前目录，不会移动
cd -      # 返回上一次所在的目录
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;pwd&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;pwd&lt;/code&gt; 用于打印当前工作目录，显示的是目前所在的绝对路径。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pwd       # 显示当前目录的绝对路径
pwd -P    # 显示物理路径
pwd -L    # 显示逻辑路径
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;ls&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ls&lt;/code&gt; 用于列出目录内容，显示当前目录或者指定目录下的文件和文件夹名称，并通过选项显示更多信息（如权限、大小、修改时间等）。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ls &amp;lt;option&amp;gt; &amp;lt;dir&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;option: 控制显示方式
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt;: 显示所有文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt;: 以长列表格式显示&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-lh&lt;/code&gt;: 以人类可读的方式显示文件大小，例如KB、MB&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-la&lt;/code&gt;: 同时显示隐藏文件与长列表格式&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-R&lt;/code&gt;: 递推显示子目录内容&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt;: 按修改时间排序&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-S&lt;/code&gt;: 按文件大小排序&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt;: 反向排序&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;dir: 查看的目录，默认为当前目录&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;tree&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;tree&lt;/code&gt;&lt;/strong&gt; 用于以树状结构显示目录内容。它可以清晰地展示文件夹之间的层级关系，非常适合查看项目结构、配置文档或代码目录。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tree &amp;lt;option&amp;gt; &amp;lt;dir&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt;: 显示所有文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt;: 只显示目录，不显示文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-L n&lt;/code&gt;: 限制显示层级为n层&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt;: 显示每个文件的完整路径&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--dirsfirst&lt;/code&gt;: 让目录优先显示在文件之前&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-I pattern&lt;/code&gt;: 忽略匹配的文件或目录&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;输出的结果如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;project/
├── data
│   ├── input.csv
│   └── output.csv
├── src
│   ├── main.py
│   └── utils.py
└── README.md
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;stat&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;stat&lt;/code&gt; 用于显示文件或文件系统的详细状态信息。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;stat example.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输出：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  File: example.txt
  Size: 2048       Blocks: 8          IO Block: 4096   regular file
Device: 802h/2050d Inode: 1234567     Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 501/ ryan)   Gid: (  20/   staff)
Access: 2025-10-24 21:52:30.000000000 +0800
Modify: 2025-10-24 21:45:18.000000000 +0800
Change: 2025-10-24 21:45:19.000000000 +0800
 Birth: 2025-10-22 09:12:00.000000000 +0800
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Access: 最后一次读取文件的时间&lt;/li&gt;
&lt;li&gt;Modify: 最后一次修改文件的时间&lt;/li&gt;
&lt;li&gt;Change: 文件元数据（权限、所有者等）最后一次被更改的时间&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;rename&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;rename&lt;/code&gt; 是 Linux 中用于批量重命名文件的命令，特别适合一次性修改多个文件名（比如批量替换、添加前缀/后缀、大小写转换等）。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rename &apos;s/原模式/新模式/&apos; &amp;lt;file_list&amp;gt;
rename &apos;s/\.txt$/.md/&apos; *.txt  # 把所有.txt文件改为.md
rename &apos;s/^/new_/&apos; *          # 把所有文件名前面加上前缀new_
rename &apos;s/ /_/g&apos; *            # 所有文件名中的空格改为下划线_
rename &apos;y/A-Z/a-z/&apos; *         # 把所有大写字母改为小写
rename &apos;s/^test_//&apos; test_*    # 去掉所有文件名的前缀test_
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;file&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;file&lt;/code&gt; 用于判断文件类型。它不会依赖文件拓展名（比如.txt, .jpg）而是通过读取文件头magic number来识别文件的真实类型。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;file &amp;lt;option&amp;gt; &amp;lt;filename&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;md5sum&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;md5sum&lt;/code&gt;计算文件的MD5校验值，用于验证文件完整性。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;md5sum file.txt
# 输出类似：
# d41d8cd98f00b204e9800998ecf8427e  file.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;find&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;find&lt;/code&gt;递归查找文件或目录，可以按名称、大小、修改时间等条件搜索。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;find &amp;lt;path&amp;gt; [option] &amp;lt;expression&amp;gt;
find /home -name &quot;*.txt&quot;  # 在 /home 下查找所有 .txt 文件
find . -type f -size +10M # 查找当前目录下大于 10MB 的文件
find /var/log -mtime -3   # 查找 3 天内修改过的日志文件
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;-name &amp;lt;pattern&amp;gt;：按文件名匹配&lt;/li&gt;
&lt;li&gt;-type &amp;lt;f|d&amp;gt;：搜索文件(f)或目录(d)&lt;/li&gt;
&lt;li&gt;-size +10M：搜索大于 10MB 的文件&lt;/li&gt;
&lt;li&gt;-mtime -3：搜索 3 天内修改的文件&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;which&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;which&lt;/code&gt;显示命令的可执行文件路径。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;which python3
# 输出：/usr/bin/python3
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;whereis&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;whereis&lt;/code&gt;查找命令的二进制文件、源代码和手册页位置。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;whereis ls
# 输出：ls: /bin/ls /usr/share/man/man1/ls.1.gz
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;chown&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;chown&lt;/code&gt;修改文件或目录的所有者与所属组。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo chown user:group file.txt      # 将 file.txt 所有者改为 user，组改为 group
sudo chown -R admin:staff /var/www  # 递归修改 /var/www 目录及其子文件权限
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;chmod&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;chmod&lt;/code&gt;修改文件或目录的读、写、执行权限。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;chmod [OPTION] &amp;lt;mode&amp;gt; &amp;lt;filename&amp;gt;
chmod 755 run.sh    # 所有者可读写执行，其他人可读执行
chmod u+x script.sh # 给文件拥有者添加执行权限
chmod -R 644 *.txt  # 递归设置所有 txt 文件为只读
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;r（读）= 4&lt;/li&gt;
&lt;li&gt;w（写）= 2&lt;/li&gt;
&lt;li&gt;x（执行）= 1&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;grep&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;grep&lt;/code&gt;在文件中搜索匹配字符串。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;grep [OPTION] &amp;lt;pattern&amp;gt; &amp;lt;file&amp;gt;
grep &quot;error&quot; log.txt                 # 查找 log.txt 中包含 “error” 的行
grep -i &quot;warning&quot; log.txt            # 忽略大小写搜索 “warning”
grep -rn &quot;main()&quot; ./src              # 递归搜索源码目录中包含 main() 的文件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常用选项：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-i：忽略大小写&lt;/li&gt;
&lt;li&gt;-n：显示行号&lt;/li&gt;
&lt;li&gt;-r：递归搜索目录&lt;/li&gt;
&lt;li&gt;-v：显示不匹配的行&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;cat&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;cat&lt;/code&gt;查看文件内容或合并多个文件。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat [OPTION] &amp;lt;filename&amp;gt;
cat file.txt                         # 显示 file.txt 内容
cat -n code.c                        # 显示带行号的 code.c 文件
cat part1.txt part2.txt &amp;gt; all.txt    # 合并两个文件为 all.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;-n：显示行号&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;head&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;head&lt;/code&gt;显示文件开头的若干行。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;head [OPTION] &amp;lt;filename&amp;gt;
head -n 10 data.csv                  # 显示 data.csv 前 10 行
head -n 1 users.txt                  # 显示文件首行
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;tail&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;tail&lt;/code&gt;显示文件末尾的若干行，常用于查看日志。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tail [OPTION] &amp;lt;filename&amp;gt;
tail -n 20 access.log                # 查看 access.log 最后 20 行
tail -f /var/log/syslog              # 实时跟踪系统日志输出
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;:::note[Reference]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/linux-commands&quot;&gt;Top 50+ Linux Commands You MUST Know&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.aliyun.com/article/1635488&quot;&gt;一张图带你学习Linux文件权限，简单易懂！&lt;/a&gt;
:::&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>JDK21新特性</title><link>https://lllirunze.cn/posts/jdk21/</link><guid isPermaLink="true">https://lllirunze.cn/posts/jdk21/</guid><description>JDK21共有15个新特性，这篇文章会介绍一些该版本的正式特性进行详细介绍。</description><pubDate>Sat, 18 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;JDK21是LTS（长期支持版），共有15个新特性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;8个正式特性&lt;/li&gt;
&lt;li&gt;6个预览版特性&lt;/li&gt;
&lt;li&gt;1个处于孵化阶段特性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们在这里介绍这些正式特性。&lt;/p&gt;
&lt;h2&gt;JEP 431 有序集合&lt;/h2&gt;
&lt;p&gt;JDK21在集合框架中新增了&lt;code&gt;SequencedCollection&lt;/code&gt;, &lt;code&gt;SequencedSet&lt;/code&gt;, &lt;code&gt;SequencedMap&lt;/code&gt;接口。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/images/posts/java/SequencedCollection.png&quot; alt=&quot;sequenced-collection&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SequencedCollection&lt;/code&gt;定义的方法如下。它主要定义了在两端添加、删除、获取元素，以及&lt;code&gt;reverse()&lt;/code&gt;方法。同理，&lt;code&gt;SequencedMap&lt;/code&gt;也定义了类似方法。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public interface SequencedCollection&amp;lt;E&amp;gt; extends Collection&amp;lt;E&amp;gt; {
    // 新引入的方法
    SequencedCollection&amp;lt;E&amp;gt; reversed();
    
    void addFirst(E);
    void addLast(E);
    E getFirst();
    E getLast();
    E removeFirst();
    E removeLast();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;JEP 439 分代ZGC&lt;/h2&gt;
&lt;p&gt;ZGC 拥有极致的性能，有几个重要特性&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;并发收集，并且使用了染色指针、读屏障等技术&lt;/li&gt;
&lt;li&gt;低延迟，承诺停顿时间小于 1ms (刚开始引入时是 10ms)&lt;/li&gt;
&lt;li&gt;基于 Region，支持的堆内存范围是 16MB ~ 16TB&lt;/li&gt;
&lt;li&gt;与 G1 相比，ZGC 对应用程序吞吐量的影响小于 15%&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在 Java 21 之前，ZGC 是不分代的，不区分新生代和老年代，都使用同一套回收算法。虽然整体性能很出色，但是仍然有性能优化的空间，因为新生代的对象存活时间较短，具有更高的回收价值。&lt;/p&gt;
&lt;p&gt;Java 21 对此做了性能优化，实现了 ZGC 的分代收集，更频繁地对新生代进行垃圾收集。在 ZGC 的基础上，分代 ZGC 有以下新特性。&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;GC CPU 开销更小&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;目前，分代 ZGC 是更好的解决方案，适用于绝大多数场景。在后续的版本中，非分代 ZGC 会逐渐废弃，以减少维护成本。&lt;/p&gt;
&lt;p&gt;在JVM参数中配置如下参数即可开启分代ZGC&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-Xmx100m
-Xlog:gc:file=/Users/jason315/Desktop/gc/zgc-gen.log
-Xlog:gc*:file=/Users/jason315/Desktop/gc/zgc-gen-detail.log
-XX:+UseZGC
-XX:+ZGenerational
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;JEP 440 Record模式&lt;/h2&gt;
&lt;p&gt;Records表示一种特殊的类，极大地简化了不可变类的定义。Record 模式增强了 Java 编程语言以便于解构 Record 对象的值，这可以嵌套 Record 模式和 Type 模式，实现强大的、声明式的和可组合的数据处理形式.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;record Point(int x, int y) {}

// Java 21 写法
static void printSumInJava21(Object obj) {
    if (obj instanceof Point(int x, int y)) {
        System.out.println(x+y);
    }
}

public static void main(String[] args) {
    Point point = new Point(3, 6);
    printSumInJava21(point);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;JEP 441 switch模式匹配&lt;/h2&gt;
&lt;p&gt;switch 表达式支持更多的类型，并且支持模式匹配，自动解构赋值。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;static String formatterPatternSwitch(Object obj) {
    return switch (obj) {
        case Integer i -&amp;gt; String.format(&quot;int %d&quot;, i);
        case Long l    -&amp;gt; String.format(&quot;long %d&quot;, l);
        case Double d  -&amp;gt; String.format(&quot;double %f&quot;, d);
        case String s  -&amp;gt; String.format(&quot;String %s&quot;, s);
        default        -&amp;gt; obj.toString();
    };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;JEP 444 虚拟线程&lt;/h2&gt;
&lt;p&gt;虚拟线程是 Java 21 最受关注的正式特性。虚拟线程，也就是轻量级线程。虚拟线程极大地降低了高吞吐量应用的开发和维护成本。&lt;/p&gt;
&lt;p&gt;平台线程（原有线程）是在 OS 线程上做的封装，它的创建和切换成本很高，可用的线程数量也有限制。对于并发较高的应用，想要提高系统的吞吐量，之前一般是做异步化，但这种方式很难定位线上问题。&lt;/p&gt;
&lt;p&gt;虚拟线程的资源分配和调度由 Java 平台实现，它不再直接与 OS 线程强关联，而是直接将平台线程作为载体线程，这使得虚拟线程的可用数量大大增加。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/images/posts/java/virtual-threads.png&quot; alt=&quot;VT&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;应用场景&lt;/h3&gt;
&lt;p&gt;虚拟线程在如下两种场景下，才能大幅提高应用系统的吞吐量&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;并发任务量很大（万级）&lt;/li&gt;
&lt;li&gt;线程工作量不会使 CPU 受限（不是 CPU 密集型任务）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;虚拟线程创建方式&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;class Task implements Runnable{
    @Override
    public void run() {
        Thread currentThread = Thread.currentThread();
        long threadId = currentThread.threadId();
        System.out.printf(&quot;[%d]Task start to run...\n&quot;, threadId);
        int sum = IntStream.range(0, 100).sum();
        System.out.printf(&quot;[%d]sum=%d, 线程名称: &apos;%s&apos;, 是否虚拟线程: %s\n&quot;, threadId, sum, currentThread.getName(), currentThread.isVirtual());
        System.out.printf(&quot;[%d]Task end.\n&quot;, threadId);
    }
}

// 方式一：直接启动，虚拟线程名称为空
private void way1() {
    Thread.startVirtualThread(new Task());
}

// 方式二：Builder 模式构建
private void way2() {
    Thread vt = Thread.ofVirtual()
        .name(&quot;VirtualWorker-&quot;, 1)
        .unstarted(new Task());
    vt.start();
}

// 方式三：Factory 模式构建
private void way3() {
    ThreadFactory factory = Thread.ofVirtual()
        .name(&quot;VirtualFactoryWorker-&quot;, 1)
        .factory();
    Thread vt = factory.newThread(new Task());
    vt.start();
}

// 方式四：newVirtualThreadPerTaskExecutor
private void way4() {
    try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
        executor.submit(new Task());
    }
}

// 方式五：构建&quot;虚拟线程池&quot;
private void way5() {
    ThreadFactory factory = Thread.ofVirtual()
        .name(&quot;VirtualFactoryWorker-&quot;, 1)
        .factory();
    ExecutorService executorService = Executors.newThreadPerTaskExecutor(factory);
    executorService.submit(new Task());
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;JEP 449 废弃32位x86架构Windows移植&lt;/h2&gt;
&lt;p&gt;Java 21宣布废弃对32位x86架构Windows的移植。&lt;/p&gt;
&lt;h2&gt;JEP 451 准备禁用代理的动态加载&lt;/h2&gt;
&lt;p&gt;当代理在运行中的 JVM 中动态加载时，会发出警告。这些警告的目的是让用户为将来的版本做好准备，将来的版本默认不允许动态加载代理，以提高 Java 安全性。&lt;/p&gt;
&lt;p&gt;在任何版本中，Java 自带的工具在启动时加载代理不会发出警告。&lt;/p&gt;
&lt;h2&gt;JEP 452 密钥封装机制API&lt;/h2&gt;
&lt;p&gt;KEM（Key Encapsulation Mechanism，密钥封装机制）是一种加密技术，它允许两个通信方安全地共享一个秘密密钥，而无需通过不安全的通道直接传输密钥。KEM 通常与对称加密算法结合使用，以实现高效的数据加密和安全通信。&lt;/p&gt;
&lt;p&gt;加密时，传统方法是使用公钥随机生成一个对称密钥，但这需要填充，也难以保证安全性。而密钥封装机制（KEM）则利用公钥的属性派生出一个相关的对称密钥，这种方法不需要填充。&lt;/p&gt;
&lt;p&gt;Java 平台传统的加密方式无法抵御量子攻击，而 KEM API 则可以有效弥补这个短板。&lt;/p&gt;
&lt;h3&gt;KEM API&lt;/h3&gt;
&lt;p&gt;KEM API 相关的接口和类都位于&lt;code&gt;javax.crypto&lt;/code&gt;包下。&lt;/p&gt;
&lt;p&gt;Java 21 新增了&lt;code&gt;KEMSpi&lt;/code&gt;（KEM Service Provider Interface），其中包括&lt;code&gt;EncapsulatorSpi&lt;/code&gt;和&lt;code&gt;DecapsulatorSpi&lt;/code&gt;。Java 提供的默认实现是 DHKEM，即 Diffie-Hellman KEM。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public interface KEMSpi {
    EncapsulatorSpi engineNewEncapsulator(PublicKey var1, AlgorithmParameterSpec var2, SecureRandom var3) throws InvalidAlgorithmParameterException, InvalidKeyException;

    DecapsulatorSpi engineNewDecapsulator(PrivateKey var1, AlgorithmParameterSpec var2) throws InvalidAlgorithmParameterException, InvalidKeyException;

    public interface DecapsulatorSpi {
        SecretKey engineDecapsulate(byte[] var1, int var2, int var3, String var4) throws DecapsulateException;
        int engineSecretSize();
        int engineEncapsulationSize();
    }

    public interface EncapsulatorSpi {
        KEM.Encapsulated engineEncapsulate(int var1, int var2, String var3);
        int engineSecretSize();
        int engineEncapsulationSize();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;:::note[Reference]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://openjdk.org/projects/jdk/21/&quot;&gt;JDK 21&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://juejin.cn/post/7383311950174339110&quot;&gt;JDK 21 正式特性全面体验&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://javaguide.cn/java/new-features/java21.html#jep-440-%E8%AE%B0%E5%BD%95%E6%A8%A1%E5%BC%8F&quot;&gt;Java 21 新特性概览（重要）&lt;/a&gt;
:::&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>SpringBoot的定时任务实现方式</title><link>https://lllirunze.cn/posts/spring-scheduled/</link><guid isPermaLink="true">https://lllirunze.cn/posts/spring-scheduled/</guid><description>在现代软件开发中，定时任务是一种常见的需求，用于执行周期性的任务或在特定的时间点执行任务。SpringBoot提供了简单的定时任务功能，使开发人员能够轻松地管理和执行这些任务。</description><pubDate>Sat, 11 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在现代软件开发中，定时任务是一种常见的需求，用于执行周期性的任务或在特定的时间点执行任务。这些任务可能涉及数据同步、数据备份、报表生成、缓存刷新等方面，对系统的稳定性和可靠性有着重要的影响。SpringBoot提供了强大且简单的定时任务功能，使开发人员能够轻松地管理和执行这些任务。&lt;/p&gt;
&lt;p&gt;本文讲述&lt;strong&gt;SpringBoot中定时任务&lt;/strong&gt;的基本用法、高级特性以及最佳实践，帮助开发人员更好地理解和应用定时任务，提高系统的稳定性和可靠性。&lt;/p&gt;
&lt;h2&gt;@Scheduled注解&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;@Scheduled&lt;/code&gt;注解是Spring提供的一个注解，用于标记方法作为定时任务执行。&lt;code&gt;@Scheduled&lt;/code&gt;注解在源码中包含一些重要属性：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
@Repeatable(Schedules.class)  
public @interface Scheduled {
    String cron() default &quot;&quot;;
	long fixedDelay() default -1;
	long fixedRate() default -1;
	long initialDelay() default -1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cron&lt;/code&gt;: 标准的Unix Cron表达式，用于定义复杂的计划执行时间&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fixedRate&lt;/code&gt;: 以固定的频率执行任务，指定两次执行之间的间隔时间（单位是毫秒）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fixedDelay&lt;/code&gt;: 在每次任务完成后等待一定的时间再进行下一次执行，指定连续执行之间的延迟时间&lt;/li&gt;
&lt;li&gt;&lt;code&gt;initialDelay&lt;/code&gt;: 首次执行前的延迟时间&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用例如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * cron属性可以设置指定时间执行  
 */  
@Scheduled(cron = &quot;0 45 14 ? * *&quot;)  
public void fixTimeExecution() {  
	System.out.println(&quot;指定时间 &quot;+dateFormat.format(new Date())+&quot;执行&quot;);  
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;SchedulingConfigurer基于接口&lt;/h2&gt;
&lt;p&gt;首先在项目中导入依赖包&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;parent&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-boot-starter&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;2.0.4.RELEASE&amp;lt;/version&amp;gt;
&amp;lt;/parent&amp;gt;
 
&amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;&amp;lt;!--添加Web依赖 --&amp;gt;
        &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
    &amp;lt;dependency&amp;gt;&amp;lt;!--添加MySql依赖 --&amp;gt;
         &amp;lt;groupId&amp;gt;mysql&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;mysql-connector-java&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
    &amp;lt;dependency&amp;gt;&amp;lt;!--添加Mybatis依赖 配置mybatis的一些初始化的东西--&amp;gt;
        &amp;lt;groupId&amp;gt;org.mybatis.spring.boot&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;mybatis-spring-boot-starter&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;1.3.1&amp;lt;/version&amp;gt;
    &amp;lt;/dependency&amp;gt;
    &amp;lt;dependency&amp;gt;&amp;lt;!-- 添加mybatis依赖 --&amp;gt;
        &amp;lt;groupId&amp;gt;org.mybatis&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;mybatis&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;3.4.5&amp;lt;/version&amp;gt;
        &amp;lt;scope&amp;gt;compile&amp;lt;/scope&amp;gt;
    &amp;lt;/dependency&amp;gt;
&amp;lt;/dependencies&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;开启本地数据库mysql，打开一个查询窗口，执行脚本内容，例子如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DROP DATABASE IF EXISTS `socks`;
CREATE DATABASE `socks`;
USE `SOCKS`;
DROP TABLE IF EXISTS `cron`;
CREATE TABLE `cron`  (
  `cron_id` varchar(30) NOT NULL PRIMARY KEY,
  `cron` varchar(30) NOT NULL  
);
INSERT INTO `cron` VALUES (&apos;1&apos;, &apos;0/5 * * * * ?&apos;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后在项目中的&lt;code&gt;application.yml&lt;/code&gt;添加数据源&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;spring:
  datasource:
    url: jdbc:mysql://localhost:3306/socks
    username: root
    password: 123456
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在数据库里准备好数据后，开始编写一个定时任务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Configuration      // 1.主要用于标记配置类，兼备Component的效果。
@EnableScheduling   // 2.开启定时任务
public class DynamicScheduleTask implements SchedulingConfigurer {
    @Mapper
    public interface CronMapper {
        @Select(&quot;select cron from cron limit 1&quot;)
        public String getCron();
    }
 
    @Autowired      //注入mapper
    @SuppressWarnings(&quot;all&quot;)
    CronMapper cronMapper;
 
    /**
     * 执行定时任务.
     */
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addTriggerTask(
            //1.添加任务内容(Runnable)
            () -&amp;gt; System.out.println(&quot;执行动态定时任务: &quot; + LocalDateTime.now().toLocalTime()),
            //2.设置执行周期(Trigger)
            triggerContext -&amp;gt; {
                //2.1 从数据库获取执行周期
                String cron = cronMapper.getCron();
                //2.2 合法性校验.
                if (StringUtils.isEmpty(cron)) {
                    // Omitted Code ..
                }
                //2.3 返回执行周期(Date)
                return new CronTrigger(cron).nextExecutionTime(triggerContext);
            }
        );
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动应用即可定时执行任务。这里的好处是指需要在数据库里对执行周期进行修改即可，而不需要重启应用。如果使用第一部分的注解的话，需要先停止应用，修改代码再重启应用才能调整周期。&lt;/p&gt;
&lt;h2&gt;多线程定时任务&lt;/h2&gt;
&lt;p&gt;可以基于注解设定多线程定时任务&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Component
@EnableScheduling   // 1.开启定时任务
@EnableAsync        // 2.开启多线程
public class MultithreadScheduleTask {
    @Async
    @Scheduled(fixedDelay = 1000)  //间隔1秒
    public void first() throws InterruptedException {
        System.out.println(&quot;第一个定时任务开始 : &quot; + LocalDateTime.now().toLocalTime() + &quot;\r\n线程 : &quot; + Thread.currentThread().getName());
        System.out.println();
        Thread.sleep(1000 * 10);
    }
 
    @Async
    @Scheduled(fixedDelay = 2000)
    public void second() {
        System.out.println(&quot;第二个定时任务开始 : &quot; + LocalDateTime.now().toLocalTime() + &quot;\r\n线程 : &quot; + Thread.currentThread().getName());
        System.out.println();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两个定时任务互不影响。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;:::note[Reference]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cnblogs.com/coderacademy/p/18058208&quot;&gt;玩转SpringBoot: SpringBoot的几种定时任务实现方式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.tencent.com/developer/article/1968344&quot;&gt;SpringBoot实现定时任务的三种方式，总有一款适合你！&lt;/a&gt;
:::&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>人工智能基础</title><link>https://lllirunze.cn/posts/huawei-chuying-8/</link><guid isPermaLink="true">https://lllirunze.cn/posts/huawei-chuying-8/</guid><pubDate>Sun, 03 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;机器学习&lt;/h2&gt;
&lt;p&gt;假设用p来评估计算机程序在某任务t上的性能，若一个程序通过利用经验e在t中任务上获得了性能改善，则我们就说关于t和p，该程序对e进行了学习。&lt;/p&gt;
&lt;p&gt;机器学习的目标是，从假设空间中，即从输入空间到输出空间的模型映射空间中，寻找一个最优模型。&lt;/p&gt;
&lt;p&gt;机器学习算法的典型分类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;有监督学习：通过训练数据学到或建立一个“函数”并依此函数推测新的实例。&lt;/li&gt;
&lt;li&gt;无监督学习：通过无标签的训练数据推断一个“函数”用于描述数据中的隐藏结构。&lt;/li&gt;
&lt;li&gt;强化学习：在与环境的交互过程中通过学习策略函数以达成回报函数最大化。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;线性回归&lt;/h3&gt;
&lt;p&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;h3&gt;决策树&lt;/h3&gt;
&lt;p&gt;决策树可以认为是if-then规则的集合，其主要优点是模型可解释性好，分类速度快。&lt;/p&gt;
&lt;h3&gt;K均值聚类&lt;/h3&gt;
&lt;p&gt;k均值聚类是一种迭代求解的聚类分析算法，该算法将数据分为k组，随机选取初始的聚类中心，然后计算每个对象与各种子聚类中心之间的距离，把每个对象分配给距离它最近的聚类中心。&lt;/p&gt;
&lt;h2&gt;深度学习&lt;/h2&gt;
&lt;p&gt;深度学习是一种主要使用深度神经网络为工具的机器学习算法。深度学习源于人工神经网络的研究。深度学习通过组合低层特征形成更加抽象的高层来表示属性类别或特征，以发现数据的分布式特征表示。&lt;/p&gt;
&lt;p&gt;人工神经网络参照生物神经网络，模仿其结构和功能的数学模型或计算模型，来对函数进行估计或近似。&lt;/p&gt;
&lt;h3&gt;全连接神经网络&lt;/h3&gt;
&lt;p&gt;全连接神经网络（Fully Connected Neural Network）为ai领域种最早发明的简单人工神经网络类型。在内部，参数从输入层向输出层单向传播，有异于循环神经网络，它的内部不会构成有向环。&lt;/p&gt;
&lt;h3&gt;深度卷积神经网络&lt;/h3&gt;
&lt;p&gt;卷积神经网络（Convolutional Neural Network, CNN）是一种前馈神经网络，它的人工神经元可以响应一部分覆盖范围内的周围单元，对于图像处理问题有出色表现。&lt;/p&gt;
&lt;p&gt;卷积convolution本质上是信号/图像处理领域内的互相关（cross-correlation），一般用来提取局部特征。使用cnn的好处在于：局部链接和权值共享；平移不变性。&lt;/p&gt;
&lt;p&gt;池化pooling思想来自于视觉机制，是对信息进行抽象的过程，用来增大感受野，降低模型的参数量。&lt;/p&gt;
&lt;h3&gt;循环神经网络&lt;/h3&gt;
&lt;p&gt;循环神经网络（Recurrent Neural Network, RNN）是一类以序列数据为输入，在序列的演进方向进行递归且所有节点按链式连接的神经网络。&lt;/p&gt;
&lt;p&gt;循环神经网络具有记忆性，因此在对序列的非线性特征进行学习时具有一定优势。rnn在语音识别、语言建模、机器翻译等领域有应用，也被用于各类时间序列预报。随着跨度的增加，rnn变得难以对信息之间的关联进行有效学习。&lt;/p&gt;
&lt;p&gt;长短期记忆网络（Long Short-Term Memory, LSTM）是为了解决一般的rnn存在的长期依赖问题而设计的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;lstm中常规的神经元被储存单元替代，适合于处理和预测时间序列中间隔和延迟非常长的事件。&lt;/li&gt;
&lt;li&gt;遗忘门forget gate决定了前一时刻中memory中的是否会被记住。&lt;/li&gt;
&lt;li&gt;输入门input gate决定当前的输入有多少被保留下来。&lt;/li&gt;
&lt;li&gt;输出门output gate决定当前memory的信息有多少会被立即输出。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>开发者测试入门</title><link>https://lllirunze.cn/posts/huawei-chuying-7/</link><guid isPermaLink="true">https://lllirunze.cn/posts/huawei-chuying-7/</guid><description>单元测试（Unit Test, UT）/模块测试，是针对程序模块（软件设计的最小单位）来进行正确性检验的测试工作。</description><pubDate>Wed, 23 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;单元测试介绍&lt;/h2&gt;
&lt;p&gt;单元测试（Unit Test, UT）/模块测试，是针对程序模块（软件设计的最小单位）来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中，一个单元就是单个程序、函数、过程等；对于面向对象编程，最小单元就是方法，包括基类（超类）、抽象类、或者派生类（子类）中的方法。&lt;/p&gt;
&lt;p&gt;单元测试可以看作是编码工作的一部分，是由程序员自己来完成，最终受益者是程序员自己。程序员有责任编写功能代码，同时也有责任为自己的代码编写单元测试。执行单元测试，就是为了证明这段代码的行为和我们期望的一致。&lt;/p&gt;
&lt;p&gt;单元测试能帮助开发人员更高效的发现问题，保证代码健壮，打算能源测试在集成测试之前做，并且每次修改代码后也需要跑单元测试，保证修改代码对其他逻辑无影响。&lt;/p&gt;
&lt;p&gt;单元测试的重要性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;高效、低成本&lt;/li&gt;
&lt;li&gt;保证质量&lt;/li&gt;
&lt;li&gt;促进代码优化&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;单元测试原则-FIRST原则&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;fast快速：测试的运行速度将直接决定自动化的反馈速度，速度越快，越能提早发现问题；省去不必要浪费的时间，提高工作效率。&lt;/li&gt;
&lt;li&gt;isolated独立：每一个测试用例需要保证完全独立运行，互不依赖，这样才能保证测试运行不被干扰，从而能够并行运行甚至分布式运行，使得测试运行更加fast。&lt;/li&gt;
&lt;li&gt;repeatable可重复：每一个测试用例在运行条件不变的情况下，无论重复运行多少次，运行结果必须完全一致。&lt;/li&gt;
&lt;li&gt;self-validating自验证：测试用例必须能够自动告知（断言）运行结果，而不依赖人工判断结果正确还是错误。&lt;/li&gt;
&lt;li&gt;timely及时：编写自动化测试是一种好的习惯，为了保证能够及时得到反馈，必须及时编写自动化测试而不拖延，一旦拖延，就很难补回来。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;软件测试基础&lt;/h2&gt;
&lt;h3&gt;什么是测试&lt;/h3&gt;
&lt;p&gt;测试是通过实验方法，获得产品知识，以进行产品评估的过程。实验方法包括一定程度的：提问、学习、建模、观察和推论。&lt;/p&gt;
&lt;p&gt;测试是一个包含计划、准备、和测量活动的过程。其目的时确认被测系统的特性，并指出需求和实现之间的差异。&lt;/p&gt;
&lt;p&gt;测试的目标是减少风险差距。差距越大，测试越困难。&lt;/p&gt;
&lt;p&gt;软件测试的目标（ISTQB）：&lt;/p&gt;
&lt;ul&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;li&gt;评估产品质量&lt;/li&gt;
&lt;li&gt;验证需求实现&lt;/li&gt;
&lt;li&gt;确认达成客户期望&lt;/li&gt;
&lt;li&gt;建立质量信心&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;软件测试的目标（ISO29119）：&lt;/p&gt;
&lt;ul&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;li&gt;评估需求实现&lt;/li&gt;
&lt;li&gt;评估客户期望&lt;/li&gt;
&lt;/ul&gt;
&lt;p&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;h3&gt;测试原则&lt;/h3&gt;
&lt;p&gt;ISTQB（国际测试资质认证委员会）提出，所有测试的指导仿真，测试的7条基本原则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;测试可以显示缺陷defect的存在，但不能证明系统不存在缺陷&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;/li&gt;
&lt;li&gt;测试活动依赖于测试背景，测试背景决定测试活动&lt;/li&gt;
&lt;li&gt;&quot;Absence of errors&quot;谬误，系统发布取决于是否满足客户需求，而不是是否还有缺陷&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;测试模型&lt;/h3&gt;
&lt;p&gt;测试的基本模型为T-IBO。&lt;/p&gt;
&lt;p&gt;测试的依据包括业务需求、合同标准、法律标准和行业标准。&lt;/p&gt;
&lt;p&gt;在计算、软件工程和软件测试中，test oracle是一种决定一项测试是否通过的判断机制。test oracle的使用会要求将被测试系统的实际输出与我们所期望的输出进行比较，从而判断是否有差异。如果有差异，可能就存在缺陷。&lt;/p&gt;
&lt;p&gt;测试不仅仅局限于软件程序的测试，测试活动贯穿于软件开发过程的整个周期中。因此，需求分析、概要设计、详细设计以及编码各阶段所得到的交付件，包括设计文档、源代码、应用程序乃至随软件版本发布的资料、license、证书，都是测试的对象。&lt;/p&gt;
&lt;p&gt;测试是研发团队所有人的职责，不只是测试人员的事。&lt;/p&gt;
&lt;p&gt;测试越早开始，代价越低越好。在开发过程中越晚修正缺陷，代价就会越高。&lt;/p&gt;
&lt;p&gt;何时停止测试，需要从多个维度进行综合评估：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当达到了必要的信心级别，风险可以接受的时候&lt;/li&gt;
&lt;li&gt;当发现缺陷的代价高于缺陷发生引起的代价时&lt;/li&gt;
&lt;li&gt;当达到测试完成标准（退出/成功标准）时&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;测试可以发生在产品生命周期的各个环节/活动的环境上：&lt;/p&gt;
&lt;ul&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;li&gt;在用户beta环境&lt;/li&gt;
&lt;li&gt;在正式的生产环境&lt;/li&gt;
&lt;/ul&gt;
&lt;p&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;li&gt;结束：从完成的测试活动中收集资料，巩固测试经验、测试件、影响测试的因素和其他数据。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;测试术语&lt;/h3&gt;
&lt;p&gt;bug：是指组件或系统中的缺陷，可能导致组件或系统无法执行其所需功能，而造成功能不正常、司机、数据丢失、非正常中断等现象。&lt;/p&gt;
&lt;p&gt;error错误：人为错误，不仅指代码逻辑错误，包括产品生命周期中任何人可能的错误。&lt;/p&gt;
&lt;p&gt;fault内部缺陷/故障：期望结果与实际结果的差异。&lt;/p&gt;
&lt;p&gt;failure外部失效：是缺陷导致的后果，通常系统不能完成最初的功能、性能等。&lt;/p&gt;
&lt;p&gt;verification验证：评估产品、服务或系统是否正确实现既定的需求、规格。&lt;/p&gt;
&lt;p&gt;validation确认：保证产品、服务或系统满足客户和其他利益相关者的需求。&lt;/p&gt;
&lt;p&gt;软件质量：反应实体满足明确和隐含的需求的能力的特征的总和。软件质量是产品、组织和体系或过程的一组固有特性，反映它们满足顾客和其他相关方面要求的程度。&lt;/p&gt;
&lt;p&gt;人们通常把影响软件质量的特性称为软件质量属性，用质量模型来描述，并定义为分层模型，最基本的叫做基本质量特性，它可以由一些子质量特性定义和度量。&lt;/p&gt;
&lt;p&gt;ISO25010产品质量属性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;功能适应性：完整性、正确性、适合性&lt;/li&gt;
&lt;li&gt;性能效率：时间行为、资源利用、容量/规格&lt;/li&gt;
&lt;li&gt;兼容性：共存、互操作&lt;/li&gt;
&lt;li&gt;易用性：可识别性、易学性、易操作性、误操作保护、ui美观度、可接入性&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;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;测试分类&lt;/h3&gt;
&lt;p&gt;围绕测试的目标，人们开发了多种的测试活动与技术：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;按是否运行程序划分
&lt;ul&gt;
&lt;li&gt;静态测试&lt;/li&gt;
&lt;li&gt;动态测试&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;按阶段划分
&lt;ul&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;按测试用例的测试设计方法划分
&lt;ul&gt;
&lt;li&gt;白盒测试&lt;/li&gt;
&lt;li&gt;黑盒测试&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;按测试针对的质量目标划分
&lt;ul&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;li&gt;可靠性测试&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;测试流程&lt;/h3&gt;
&lt;p&gt;阶段测试活动：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;开发者测试：UT-&amp;gt;IT/MST-&amp;gt;BBIT&lt;/li&gt;
&lt;li&gt;系统集成与验证：SDV-&amp;gt;SIT-&amp;gt;SVT&lt;/li&gt;
&lt;li&gt;客户化测试：比拼测试-&amp;gt;准入测试-&amp;gt;客户验收测试&lt;/li&gt;
&lt;/ol&gt;
&lt;p&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;li&gt;测试执行：用例手工执行、用例自动化执行&lt;/li&gt;
&lt;li&gt;测试评估：测试评估、测试报告、产品缺陷&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;测试设计技术&lt;/h2&gt;
&lt;h3&gt;黑盒测试&lt;/h3&gt;
&lt;h4&gt;等价类EP（Equivalence Partitioning）&lt;/h4&gt;
&lt;p&gt;等价类划分法是一种最基础的黑盒测试用例设计方法。它不考虑程序内部结构，唯一依据是软件需求规格说明书。等价类是输入条件的一个子集，该子集种的数据对于揭示程序种的错误是等价的。从每一个子集种选取具有代表性的数据生成测试用例。&lt;/p&gt;
&lt;p&gt;有效等价类：指对于系统的规格来说是合理的，有效输入数据构成的集合。&lt;/p&gt;
&lt;p&gt;无效等价类：指对于系统的规格来说是不合理或无意义的输入（即不正确的输入值）。&lt;/p&gt;
&lt;p&gt;简单等价类划分的一般规则如下：&lt;/p&gt;
&lt;ul&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;/ul&gt;
&lt;h4&gt;边界值BVA（Boundary Value Analysis）&lt;/h4&gt;
&lt;p&gt;边界值分析是一种常用的软件测试技术，旨在通过对输入参数边界值的测试，来发现程序边界条件下可能存在的错误。&lt;/p&gt;
&lt;p&gt;黑盒测试仅仅关注程序的输入，不考虑软件内部实现细节。&lt;/p&gt;
&lt;h4&gt;数据组合Combinatorial Test&lt;/h4&gt;
&lt;p&gt;数据组合将被测系统输入参数的取值进行组合，来生成测试用例。它可以覆盖任意n个因素所有取值组合，理论上可以发现由n个因素共同作用引发的缺陷。&lt;/p&gt;
&lt;p&gt;数据组合测试设计技术针对系统的需求进行分析，识别出测试因子及其可能取值，采用数据组合覆盖技术生成测试数据组合，最后生成测试用例。&lt;/p&gt;
&lt;p&gt;EC（Each Choice）组合：所有参数（因子）的可能取值至少被一个测试用例覆盖。&lt;/p&gt;
&lt;p&gt;BC（Base Choice）组合：以测试因子的基本组合为基础，每次修改一个因子的取值，直到该因子的所有取值被覆盖。&lt;/p&gt;
&lt;p&gt;N-wise组合：从多个测试因子中取n个因子进行组合，不考虑组合的顺序，当n=2时是pairwise组合，n为测试因子个数时为全组合。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pairwise组合：只考虑两个因子之间的组合，可以有效地发现因子的交互作用。&lt;/li&gt;
&lt;li&gt;全组合：考虑所有因子之间的所有组合，测试覆盖率最高，但测试用例数量也最多。&lt;/li&gt;
&lt;li&gt;n-wise组合：介于pairwise和全组合之间，可以通过调整n值来平衡测试覆盖率和测试用例数量。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;数据组合优化策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;无效值：针对选择因子中的无效值，一般不进行组合。&lt;/li&gt;
&lt;li&gt;约束条件：明确定义约束关系，并利用组合测试用具生成有效的测试用例集。&lt;/li&gt;
&lt;li&gt;复合组合策略：为了降低测试用例数量，提高测试效率。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;判定表DTT&lt;/h4&gt;
&lt;p&gt;判定表是一种充分考虑被测系统输入因子组合、约束，以及输入和输出之间因果关系的测试用例设计方法，特别适用于输入条件与输出结果之间存在明确因果关系的系统。&lt;/p&gt;
&lt;p&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;li&gt;简化判定表&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;判定点DPT&lt;/h4&gt;
&lt;p&gt;判定点逻辑覆盖通过对系统内部逻辑结构的深入分析，确保每个判定点及其所有可能条件都被测试覆盖。它与其他黑盒测试方法相比，更关注实现细节和业务逻辑，是一种偏白盒的测试分析方法。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;判定decision：在程序执行过程中，根据条件判断结果选择不同的执行路径的分支点。&lt;/li&gt;
&lt;li&gt;条件condition：判定点中包含一个或多个逻辑表达式，这些表达式通过逻辑运算（与、或、非）组合而成，最终结果为真或假。&lt;/li&gt;
&lt;li&gt;逻辑覆盖：通过设计测试用例，使得流程中的每个判定点的所有可能结果都被执行到，以及每个条件的所有可能取值都被覆盖到。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;处理周期PCT&lt;/h4&gt;
&lt;p&gt;路径覆盖：软件系统功能的业务逻辑可以适用流程图进行描述，系统的业务逻辑流程图往往包含一条或多条业务路径，路径覆盖的对象就是这些路径的组合。&lt;/p&gt;
&lt;p&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;/ol&gt;
&lt;h4&gt;状态转换测试STT&lt;/h4&gt;
&lt;p&gt;N-switch覆盖是指对被状态图中的所有n+1次连续状态转换的序列的覆盖。 通过对进行被测系统分析，得到系统业务逻辑的状态迁移图，n-switch覆盖的对象就是状态迁移图中的状态转换序列。&lt;/p&gt;
&lt;h3&gt;白盒测试&lt;/h3&gt;
&lt;p&gt;白盒测试是根据被测对象的结构设计测试用例的一种方法。这里的结构包括：&lt;/p&gt;
&lt;ul&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;/ul&gt;
&lt;p&gt;语句覆盖：要求每条可执行语句至少执行一次。&lt;/p&gt;
&lt;p&gt;判定覆盖：也叫分支覆盖，每个判断的真值和假值至少执行一次。&lt;/p&gt;
&lt;p&gt;条件覆盖：要求程序中的每个条件的真值和假值至少执行一次。&lt;/p&gt;
&lt;p&gt;判定-条件覆盖：要求每个判定的真值和假值至少执行一次，并且每个条件的真值和假值也至少执行一次。&lt;/p&gt;
&lt;p&gt;条件组合覆盖：也叫多重条件覆盖，每个判定的条件取值组合至少执行一次。&lt;/p&gt;
&lt;p&gt;MC/DC（Modified Condition/Decision Coverage）修正条件/判定覆盖，是一种严格的逻辑覆盖准则。它要求：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个条件在判定中至少被赋值为真和假一次&lt;/li&gt;
&lt;li&gt;每个判定的每个结果至少被触发一次&lt;/li&gt;
&lt;li&gt;每个条件必须能够独立影响判定的输出&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;路径覆盖：覆盖程序中所有可能的路径。路径是指程序从入口到所有出口的执行路径。&lt;/p&gt;
</content:encoded></item><item><title>Java语言编程规范</title><link>https://lllirunze.cn/posts/huawei-chuying-6/</link><guid isPermaLink="true">https://lllirunze.cn/posts/huawei-chuying-6/</guid><description>避免使用魔鬼数字（难以理解的数字或字符串），要使用有意义的常量来代替。</description><pubDate>Thu, 10 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;规范刷新流程：提交评论/mr -&amp;gt; 规范组讨论 -&amp;gt; 达成一致 -&amp;gt; 修改/合入mr -&amp;gt; 发布评审 -&amp;gt; 发布正式版本&lt;/p&gt;
&lt;h2&gt;代码风格&lt;/h2&gt;
&lt;h3&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;接口、类、注解、枚举类型&lt;/td&gt;
&lt;td&gt;大驼峰，测试类加Test后缀，文件名为&lt;code&gt;顶层类名.java&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;类的属性、局部变量、方法、方法参数&lt;/td&gt;
&lt;td&gt;小驼峰，测试方法可以有下划线&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;静态常量、枚举值&lt;/td&gt;
&lt;td&gt;全大写，下划线分割&lt;code&gt;_&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;泛型类型变量&lt;/td&gt;
&lt;td&gt;单个大写字母，可借一个数字或者接下划线加若干个大写字母&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;异常&lt;/td&gt;
&lt;td&gt;加后缀Exception或Error&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;规范中的常量是指不可被修改的field和枚举常量。“不可被修改”需要同时满足以下两个条件：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;field的值/对象不可被修改为其他的值/对象&lt;/li&gt;
&lt;li&gt;field为对象类型时，对象在初始化完成后其属性不能被修改&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;常量定义的一般格式为&lt;code&gt;[访问修饰符] static final 类型 常量名 = 常量值;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;常量有一些注意事项：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;常量的命名要尽量表达完整的语义。&lt;/li&gt;
&lt;li&gt;避免使用魔鬼数字（难以理解的数字或字符串），要使用有意义的常量来代替。&lt;/li&gt;
&lt;li&gt;不建议使用常量类集中管理所有的常量，推荐按功能进行管理，就近定义常量。&lt;/li&gt;
&lt;li&gt;mutable对象禁止定义为常量。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;注释&lt;/h3&gt;
&lt;p&gt;注释使用的总体原则是：按需注释。&lt;/p&gt;
&lt;ul&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;/ul&gt;
&lt;p&gt;JavaDoc中有几个要求：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;要对public、protected修饰的元素添加JavaDoc修饰。&lt;/li&gt;
&lt;li&gt;顶层public类的JavaDoc应该包含功能说明和创建日期/版本信息。&lt;/li&gt;
&lt;li&gt;方法的JavaDoc中应该包含功能说明，根据时机需要按顺序使用&lt;code&gt;@param, @return, @throws&lt;/code&gt;标签对参数、返回值、异常进行注释。&lt;/li&gt;
&lt;li&gt;不要添加空有格式的方法头注释。&lt;/li&gt;
&lt;li&gt;涉及线程安全时，要进行相关的说明。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;代码注释的时候，&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;非首行代码的注释应该与前面的代码之间加一空行。&lt;/li&gt;
&lt;li&gt;代码右侧的注释，代码、注释符、注释之间至少留一个空格。&lt;/li&gt;
&lt;li&gt;正式交付的代码不应包含TODO/FIXME注释。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;格式&lt;/h3&gt;
&lt;p&gt;在编码规范的指导下，审慎地编排代码以使代码尽可能清晰、风格统一。&lt;/p&gt;
&lt;h4&gt;源文件排版&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Java源文件一般按顺序包含版权、package、import、顶层类，其用空行分隔。&lt;/li&gt;
&lt;li&gt;import包应该按照先安卓、其他商业组织、其他开源第三方、net/org开源组织、最后java的分类顺序出现，并用一个空行分组。&lt;/li&gt;
&lt;li&gt;一个类的声明部分应该按照类变量、静态初始化块、实例变量、实例初始化块、构造方法、方法的顺序排列，且用空行分隔。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;大括号：推荐使用K&amp;amp;R风格&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;条件语句和循环块中要使用大括号。&lt;/li&gt;
&lt;li&gt;左大括号不换行。&lt;/li&gt;
&lt;li&gt;右大括号自己单独一行。&lt;/li&gt;
&lt;li&gt;右大括号后，可以跟逗号、分号等，也可以跟随else、catch、finally等关键字语句。&lt;/li&gt;
&lt;li&gt;对于空块，除了K&amp;amp;R风格外，也可以在大括号打开后立即关闭，但是要保持空块风格一致。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;行宽和可读性&lt;/h4&gt;
&lt;p&gt;代码行宽上限不取决于屏幕宽度，而是人眼跟踪范围。每行建议不要超过120个窄字符。&lt;/p&gt;
&lt;h4&gt;换行：换行时建议操作符、连接符放在新的一行&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;当在非赋值运算符处断行时，中断点出现在符号之前。这也适用以下“类似运算符”的符号：
&lt;ul&gt;
&lt;li&gt;点分隔符&lt;code&gt;.&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;方法引用的两个冒号&lt;code&gt;::&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;类型限定中的&amp;amp;符号&lt;code&gt;&amp;lt;T extends Foo &amp;amp; Bar&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;catch块中的管道&lt;code&gt;catch (FooException | BarException e)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;方法或构造方法名称与紧跟在其后面的左括号保持在同一行。&lt;/li&gt;
&lt;li&gt;逗号断点出现在逗号之后。&lt;/li&gt;
&lt;li&gt;在lambda表达式中，如果箭头后面时单个表达式，可以在箭头后面出现断点，如果箭头后是程序块，可以在大括号后出现断点。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;水平空格&lt;/h4&gt;
&lt;p&gt;代码中的水平空格只能使用单个空格或多个空格的组合：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;缩进时使用4个空格，不要使用制表符（tab）；代码块的缩进级别应该与上下文代码相同。&lt;/li&gt;
&lt;li&gt;使用空格突出关键字和重要信息。单个空格应该分隔关键字与其后的左括号、与其前面的大括号，出现在任何二元/三元运算符/类似运算符的两侧，&lt;code&gt;, : ;&lt;/code&gt;或类型转换结束括号&lt;code&gt;)&lt;/code&gt;之后使用空格。&lt;/li&gt;
&lt;li&gt;行尾和空行不应有空格。&lt;/li&gt;
&lt;li&gt;不建议使用空格使代码垂直对齐。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;字面量&lt;/h4&gt;
&lt;p&gt;数字字面量应该设置合理的后缀来指定数值的类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;float类型的字面量，可以使用&lt;code&gt;F, f&lt;/code&gt;作为后缀。&lt;/li&gt;
&lt;li&gt;double类型的字面量，可以使用&lt;code&gt;D, d&lt;/code&gt;作为后缀。&lt;/li&gt;
&lt;li&gt;long类型的字面量，只能使用&lt;code&gt;L&lt;/code&gt;作为后缀，防止&lt;code&gt;l&lt;/code&gt;与数字1混淆。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于较大数值，可以考虑使用数字下划线分隔符来增加代码的可读性，例如&lt;code&gt;30_000_000_000L&lt;/code&gt;。&lt;/p&gt;
</content:encoded></item><item><title>Java实战应用</title><link>https://lllirunze.cn/posts/huawei-chuying-5/</link><guid isPermaLink="true">https://lllirunze.cn/posts/huawei-chuying-5/</guid><description>代理模式是指通过代理对象代替目标对象完成相应操作，并能够在操作执行的前后进行增强处理。</description><pubDate>Mon, 28 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;变量应用进阶&lt;/h2&gt;
&lt;h3&gt;变量类型汇总&lt;/h3&gt;
&lt;p&gt;Java是一种强类型语言，通过变量的类型限制了变量可以持有值（以及表达式可以产生的值），限制在各类值上支持的操作，并确定操作的含义。Java也是一种静态语言，在编译时检测数据类型是否匹配，便于开发者及时发现编码错误。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基本数据类型：byte, short, int, long, float, double, char, boolean&lt;/li&gt;
&lt;li&gt;引用数据类型：类、接口、数组、枚举、注解&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所有变量在使用前必须声明和初始化。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 基本格式
type identifier [= value][, identifier [= value]...];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;类变量、实例变量支持默认初始化，局部变量必须显示初始化。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java基本类型的长度固定，与操作系统位宽无关。&lt;/li&gt;
&lt;li&gt;long、float、double类型可以在数值后添加L、f、d表示数字代表的类型。&lt;/li&gt;
&lt;li&gt;默认值时类变量、实例变量，以及数组元素的默认初始化的赋值，而其他变量（如临时变量）必须显示初始化。&lt;/li&gt;
&lt;li&gt;由于程序中存储数值是存在边界的，如果计算过程中导致超过这个边界，则会得到期望之外的结果。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;数据类型转换&lt;/h3&gt;
&lt;p&gt;Java中进行赋值时，要求等号左边和右边的类型要一致，如果不一致，就需要进行数值类型转换：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;自动类型转换：容量小的类型自动转换为容量大的类型&lt;/li&gt;
&lt;li&gt;强制类型转换：大转小&lt;/li&gt;
&lt;li&gt;隐含强制类型转换（初始化）：在类型初始化时，int会隐含强制转换成低级别的byte和short类型&lt;/li&gt;
&lt;li&gt;其他类型转换：包装类、字符串、基本类型直接的转换&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;无论自动和强制类型转换，都要遵循如下基本原则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不能对boolean类型进行类型转换&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;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;引用类型和拆装箱&lt;/h3&gt;
&lt;p&gt;基本数据类型部分场景下不能使用，为了扩展8种基本数据类型相关的常用功能，JDK为每个基本数据类型涉及了一个对应类，叫做包装类。包装类的主要用途由2种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;作为基本数据类型对应的类型在，方便有关对象的操作。&lt;/li&gt;
&lt;li&gt;可以用设定每种基本数据类型的属性大小和使用方法。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;装箱：基本类型-&amp;gt;包装类，拆箱：包装类-&amp;gt;基本类型。拆装箱影响性能，应尽量避免反复拆装箱。&lt;/p&gt;
&lt;h2&gt;表达式&lt;/h2&gt;
&lt;h3&gt;基本运算符存在的风险&lt;/h3&gt;
&lt;p&gt;对于&lt;code&gt;int multi(int n1, int n2) { return n1 * n2; }&lt;/code&gt;中，当n1和n2的绝对值较大，两者的乘积越界溢出时，方法就无法正确的计算结果。当无法预判乘积结果是否会溢出时，可以使用Java 8新增的&lt;code&gt;Math.multiplyExact()&lt;/code&gt;方法，该方法在乘积运算不产生溢出时会返回运算结果，溢出时抛出ArithmeticException。&lt;/p&gt;
&lt;p&gt;由于计算机中的精确缺失，浮点符不能直接使用==或!=判断是否相等，而应该基于两者之差与极小值比较大小的方式判断是否相等。&lt;/p&gt;
&lt;p&gt;逻辑运算符存在“短路”场景，即如果基于操作符和第一个操作数和就可以得到结果，则不会再执行第二个操作数的计算。&lt;/p&gt;
&lt;p&gt;运算符注意优先级：https://blog.csdn.net/sunshihua12829/article/details/47912123&lt;/p&gt;
&lt;h3&gt;Lambda表达式&lt;/h3&gt;
&lt;p&gt;Lambda表达式可以替换匿名类，简化代码。Java Lambda表达式中可以使用局部变量，但是不可修改，相当于局部变量为final类型，遵循“无副作用”。&lt;/p&gt;
&lt;p&gt;有些场景的代码执行后，结果不一定会被使用，从而造成性能浪费。Lambda表达式是延迟执行的，这正好可以作为解决方案提升性能。&lt;/p&gt;
&lt;p&gt;如果Lambda表达式实现体只调用了一个外部已经存在的方法时，就可以使用方法引用简化调用。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;类型&lt;/th&gt;
&lt;th&gt;语法&lt;/th&gt;
&lt;th&gt;Lambda表达式&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;静态方法引用&lt;/td&gt;
&lt;td&gt;类名::staticMethod&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(args)-&amp;gt;类名.staticMethod(args)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;实例方法引用&lt;/td&gt;
&lt;td&gt;inst::instMethod&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(args)-&amp;gt;inst.instMethod(args)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;对象方法引用&lt;/td&gt;
&lt;td&gt;类名::instMethod&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(inst, args)-&amp;gt;inst.instMethod(args)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;构建方法引用&lt;/td&gt;
&lt;td&gt;类名::new&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(args)-&amp;gt;new 类名(args)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;面向对象&lt;/h2&gt;
&lt;h3&gt;多态&lt;/h3&gt;
&lt;p&gt;对于多态，有几个注意事项：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果子类重写了父类的方法，则执行子类的方法，否则执行父类的方法。&lt;/li&gt;
&lt;li&gt;执行方法的优先级为（从高到低）：
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;this.method(Obj)&lt;/code&gt;（前提是父类有相同的定义）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;super.method(Obj)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;this.method((super)Obj)&lt;/code&gt;（前提是父类有相同的定义）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;super.method((super)Obj)&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;类加载顺序&lt;/h3&gt;
&lt;p&gt;Java的类加载机制中最重要的就是程序初始化过程，其中包含了静态资源、非静态资源、父类子类、构造方法，它们存在执行顺序：最先执行带有static关键字的属性/代码块，其次是非static关键字的属性/代码块、构造方法；同时，先父类再子类；同级别的按照代码顺序（自上而下）。具体地：&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;li&gt;子类的属性值、代码块&lt;/li&gt;
&lt;li&gt;子类的构造方法&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;权限修饰符&lt;/h3&gt;
&lt;p&gt;Java中可以使用权限修饰符控制类、类成员变量、类成员方法的访问权限：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;修饰符&lt;/th&gt;
&lt;th&gt;类内部&lt;/th&gt;
&lt;th&gt;同一个包&lt;/th&gt;
&lt;th&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;private&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(default)&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;protected&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;public&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;对于class的权限修饰只能用public和缺省default，其中，default类只可以被同一个包内部的类访问。&lt;/p&gt;
&lt;h3&gt;密封类&lt;/h3&gt;
&lt;p&gt;密封类sealed class，可以设置子类名称，密封类的子类只能是final class，sealed class或non-sealed class。非permits列表中的类不能被继承。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;interface I {}

sealed class C implements I permits D, E, F {}

non-sealed class D extends C {}
final class E extends C {}
sealed class F extends C {}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;注解&lt;/h3&gt;
&lt;p&gt;Java注解提供了一种安全的类似注释的机制，用来将任何的信息或元数据与程序元素进行关联。注解可以应用在：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;生成文档&lt;/li&gt;
&lt;li&gt;在编译时进行格式检查&lt;/li&gt;
&lt;li&gt;跟踪代码依赖性，实现替代配置文件功能&lt;/li&gt;
&lt;li&gt;在反射的class、method、field等函数中，有许多与Annotation相关的接口，可以在反射中解析并使用Annotation。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;异常&lt;/h2&gt;
&lt;p&gt;不合理使用异常会引导大量安全问题。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;如果抛出的异常对象属于catch子句中的异常类，或者属于该异常类的子类，则认为生成的异常对象与catch块捕获的异常类型相匹配。&lt;/li&gt;
&lt;li&gt;每个catch子句依次检查，一旦有子句匹配，则后面的被忽略。&lt;/li&gt;
&lt;li&gt;finally子句必定会在其他代码结束之后执行，除非程序/线程提前退出。&lt;/li&gt;
&lt;li&gt;finally执行时机在try/catch代码块退出前，即所有代码块后，跳出逻辑前。&lt;/li&gt;
&lt;li&gt;finally执行语句不会影响原有返回值，除非finally中直接return。&lt;/li&gt;
&lt;li&gt;支持自定义异常。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;throw与throws的区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;throw用于语句中抛出异常&lt;/li&gt;
&lt;li&gt;throws用于方法签名中声明可能抛出的异常&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;JDK-8支持try-with-resources方式，资源相关代码直接写在try后的括号内，异常时自动关闭相关资源，极大简化代码写法。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;try (read; br) {
  
} catch (Exception e) {
  
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;采用try-with-resources写法，当try中的代码执行结束之后就会调用try括号中的对象的close()方法来关闭资源，如果我们对try-with-resources语法代码进行反编译，可以看到里面依然是try-catch-finally写法。try-with-resources方式处理的资源类应实现了AutoCloseable接口的close()方法。&lt;/p&gt;
&lt;p&gt;JDK-9引入了更加易读的try-with-resource写法，避免try后括号内代码过多，不易读。&lt;/p&gt;
&lt;p&gt;在传递异常的时候，未对其中的敏感信息进行过滤，会导致信息泄露。&lt;/p&gt;
&lt;h2&gt;代码组织管理&lt;/h2&gt;
&lt;h3&gt;包管理Package&lt;/h3&gt;
&lt;p&gt;Java提供了包机制，用于区别类名的命名空间，从而更加清晰分层地组织所有类/源码文件。包的作用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;把职责相关的类或接口组织在同一个包中，方便类的查找和使用。&lt;/li&gt;
&lt;li&gt;包采用了树形目录的存储方式，可以避免类的名字冲突。&lt;/li&gt;
&lt;li&gt;包限定了访问权限，拥有包访问权限的类才能访问某个包中的类。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一般通过import引入包名后，代码中可以直接使用类名，特殊地，如果同一个文件中要使用名字冲突地类时，需要通过显示添加包名的方式指定。&lt;/p&gt;
&lt;h3&gt;模块化Module&lt;/h3&gt;
&lt;p&gt;模块化系统的主要目的如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;更可靠的配置，通过指定明确的类依赖关系代替以前那种易错的类路径class-path加载机制。&lt;/li&gt;
&lt;li&gt;强大的封装，允许一个组件声明它的public类型中，哪些可以被其他组件访问，哪些不可以。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;反射（动态代理）&lt;/h2&gt;
&lt;p&gt;反射reflection是指在程序的运行状态中，动态获取类信息以及动态调用对象的功能。反射就像给开发者提供了一面镜子，可以反向看到某个类中的结构信息，进而调用执行。反射常用于创建动态代理或开发通用框架，提供系统的通用性、灵活性，如Spring的IOC。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class ReflectionDemo {
  // 用反射来创建类对象
  public void create_class_object() throws xxxException {
    Class&amp;lt;Person&amp;gt; personClass = Person.class;
    Person person = personClass.getConstructor().newInstance();
    System.out.println(person.sayHi());
    
    // 其他得到personClass的方法
		Class&amp;lt;Person&amp;gt; personClass = Class.forName(&quot;com.huawei.core.reflection.bean.Person&quot;);
    Class&amp;lt;? extends Person&amp;gt; personClass = person.getClass();
    Class&amp;lt;?&amp;gt; personClass = this.getClass().getClassLoader().loadClass(&quot;com.huawei.core.reflection.bean.Person&quot;);
  }
  
  // 用反射来获取类的构造方法
  public void get_class_constructor() throws xxxException {
    Class&amp;lt;Person&amp;gt; personClass = Person.class;
    Constructor&amp;lt;Person&amp;gt; constructor = personClass.getConstructor(String.class, xxx); // 取决于构造方法的参数有什么，另外，如果构造方法不是public的话会报错
    System.out.println(&quot;constructor.getName() = &quot; + constructor.getName());
    
    Person person = constructor.newInstance(&quot;Tony&quot;, xxx);
    System.out.println(person.sayHi());
    
    // 其他获取类构造方法的方式
    Constructor&amp;lt;Person&amp;gt; constructor = personClass.getDeclaredConstructor(String.class, LocalDate.class); 
    constructor.setAccessible(true); // getDeclaredConstructor方法可以无视类构造方法的修饰符，例如private
  }
  
  // 用反射来获取类的成员方法
  public void get_class_methods() throws xxxException {
    Class&amp;lt;Person&amp;gt; personClass = Person.class;
    Method sayHi = personClass.getMethod(&quot;sayHi(成员方法名称)&quot;);
    System.out.println(&quot;sayHi.getName() = &quot; + sayHi.getName());
    
    Method study = personClass.getDeclaredMethod(&quot;study&quot;, String.class); // 成员方法如果是private之类的话要用getDeclaredMethod方法
    System.out.println(&quot;Arrays.toString(study.getParameterTypes()) = &quot; + Arrays.toString(study.getParameterTypes()));
  }
  
  // 获取成员变量或者其他信息可以用getField等方法，略
  
  // 调用成员方法
  public void invoke_class_methods() throws xxxException {
    Class&amp;lt;Person&amp;gt; personClass = Person.class;
    Method sayHi = personClass.getMethod(&quot;sayHi(成员方法名称)&quot;);
    System.out.println(sayHi.invoke(new Person()));
    
    Method study = personClass.getDeclaredMethod(&quot;study&quot;, String.class); // 成员方法如果是private之类的话要用getDeclaredMethod方法
    study.setAccessible(true);
    System.out.println(study.invode(new Person(), &quot;code&quot;));
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;动态代理&lt;/h3&gt;
&lt;p&gt;代理模式是指通过代理对象代替目标对象完成相应操作，并能够在操作执行的前后进行增强处理。&lt;/p&gt;
&lt;p&gt;代理类常用于实现日志、鉴权等通用功能。&lt;/p&gt;
&lt;p&gt;代理模式分为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;静态代理：代理类和委托类的关系在运行前就确定。但是当真实类的方法越来越多的时候，代理类对应的方法也要增加，代码量的改动大。&lt;/li&gt;
&lt;li&gt;动态代理：
&lt;ul&gt;
&lt;li&gt;JDK代理：涉及java.lang.reflect包中的InvocationHandler接口和Proxy类&lt;/li&gt;
&lt;li&gt;cglib代理&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class JDKProxy extends InvocationHandler {
  
  private Animal target;
  
  public JDKProxy(Animal target) { this.target = target; }
  
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throw Throwable {
    System.out.println(&quot;do something before &quot; + method.getName());
    method.invoke(target, args);
    System.out.println(&quot;do something after &quot; + method.getName());
    return null;
  }
  
  public Object getProxyInstance() {
    return Proxy.newProxyInstance(this.getClass.getClassLoader(), target.getClass().getInterfaces(), this);
  }
  
  public static void main(String[] args) {
    Person person = new Person();
    Animal proxyInstance = (Animal)new JDKProxy(person).getProxyInstance();
    proxyInstance.move();
    proxyInstance.rest();
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;多线程&lt;/h2&gt;
&lt;p&gt;线程thread是os能够进行运算调度的最小单位，使用多线程可以实现系统并发操作，提高资源利用率。使用多线程编码的好处：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提高cpu资源利用率：进行具有阻塞性质的操作，阻塞期间cpu不能进行工作，使用多线程可以增加程序的吞吐量。&lt;/li&gt;
&lt;li&gt;保证公平特性：多个用户或程序对系统资源具有平等优先级，使用时间片的方式可以更好的共享cpu资源。&lt;/li&gt;
&lt;li&gt;功能模块化：创建多个线程，让其并行的执行某个单独的任务，职责单一。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;普通的多线程方式包括继承Thread和实现Runnable接口两种方式。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;继承Thread：由于Java不能允许多继承，一个类如果需要继承其他类就不能再定义为线程类了。&lt;/li&gt;
&lt;li&gt;实现Runnable接口：由于接口可以多实现，一个类可以继承其他类的同时实现Runnable接口称为线程类。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;public class ThreadDemo {
  public static void main(String[] args) {
    MyThread t1 = new MyThread();
    MyThread t2 = new MyThread();
    t1.start();
    t2.start();
    
    Thread t3 = new Thread(new MyRunnable());
    Thread t4 = new Thread(new MyRunnable());
    t3.start();
    t4.start();
  }
}

// 继承Thread
class MyThread extends Thread {
  @Override
  public void run() {
    for (int i=0; i&amp;lt;10; i++) {
      System.out.println(MyThread.currentThread().getName() + &quot;: &quot; + i);
    }
  }
}

// 实现Runnable
class MyRunnable implements Runnable {
  @Override
  public void run() {
    for (int i=0; i&amp;lt;10; i++) {
      System.out.println(MyThread.currentThread().getName() + &quot;: &quot; + i);
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;线程池&lt;/h3&gt;
&lt;p&gt;公司Java编程规范中指出，建议“避免不加控制地创建新线程，应该使用线程池来管控资源”。&lt;/p&gt;
&lt;p&gt;线程池有如下优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;降低资源消耗：通过重复利用已创建的线程降低线程创建和销毁造成的消耗。&lt;/li&gt;
&lt;li&gt;提高响应速度：当任务到达时，任务可以不需要等到线程创建就能立即执行。&lt;/li&gt;
&lt;li&gt;提高线程的可管理性：线程是稀缺资源，如果无限制地创建，不仅会消耗系统资源，还会降低系统的稳定性，使用线程池可以进行统一分配、调优和监控。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ThreadPoolExecutor是线程池最基础的功能实现类，构造方法参数如下：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&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;corePoolSize&lt;/td&gt;
&lt;td&gt;核心线程池数量，一个任务到来时，如果当前没有空闲线程且线程数量小于corePoolSize，则创建一个新的线程执行这个任务。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;maximumPoolSize&lt;/td&gt;
&lt;td&gt;如果阻塞队列已满，无法继续将任务放入。如果当前线程数量小于maximumPoolSize则创建一个新的线程执行当前任务。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;keepAliveTime, unit&lt;/td&gt;
&lt;td&gt;线程空闲时间，如果当前线程数量已经大于corePoolSize或者调用了allowsCoreThreadTimeOut将线程超时关闭设置为true，则空闲这段时间后会关闭线程。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;workQueue&lt;/td&gt;
&lt;td&gt;负责任务缓冲的阻塞队列，如果当前没有空闲线程且线程数量已经等于corePoolSize，则尝试将任务放入这个阻塞队列，如果成功则等待有空闲线程取出执行。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;handler&lt;/td&gt;
&lt;td&gt;如果当前阻塞队列满，且当前线程数量已经到达maximumPoolSize，则调用handler的rejectedExecution方法处理这个任务。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;线程池创建线程的流程如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;线程数如果小于corePoolSize，创建线程执行任务，否则进入2&lt;/li&gt;
&lt;li&gt;workQueue阻塞队列如果还没满，则将任务插入阻塞队列；如果满了进入3&lt;/li&gt;
&lt;li&gt;活动线程如果小于maximumPoolSize，创建线程执行任务，否则进入4&lt;/li&gt;
&lt;li&gt;使用拒绝策略handler&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如何合理使用线程池：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cpu密集型任务应配置尽可能小的线程，如配置Ncpu+1个线程的线程池。&lt;/li&gt;
&lt;li&gt;io密集型任务的线程数量计算公式为&lt;code&gt;Nthreads = Ncpu*Ucpu*(1+W/C)&lt;/code&gt;，从而充分利用cpu资源。&lt;/li&gt;
&lt;li&gt;优先级不同的任务可以使用优先级队列PriorityBlockingQueue来处理，它可以让优先级高的任务先执行。&lt;/li&gt;
&lt;li&gt;执行时间不同的任务可以交给不同规模的线程池来处理，或者可以使用优先级队列，让执行时间短的任务先执行。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;IO编程&lt;/h2&gt;
&lt;p&gt;java.io包中提供了各种流stream的相关API，可以通过标准接口和外部设备（文件、网络等）交互，输入/输出不同类型的数据。&lt;/p&gt;
&lt;p&gt;按流的传输格式分为两种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;字节流：以字节byte为单位处理数据，适用于处理二进制数据（图片、视频）&lt;/li&gt;
&lt;li&gt;字符流：以Unicode码元char为单位处理数据，适合处理文本数据（txt等）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;NIO&lt;/h3&gt;
&lt;p&gt;Non-blocking IO（NIO）是一种非阻塞io，也称为New IO。nio主要的api包括通道channel、缓冲区buffer和选择器selector。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通道channel
&lt;ul&gt;
&lt;li&gt;channel可以读取和写入通道，流是单向的（读或写）&lt;/li&gt;
&lt;li&gt;channel可以异步读写，流是同步的（读或写）&lt;/li&gt;
&lt;li&gt;channel总是从buffer读取或向buffer写入，流可以直接读写&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;缓冲区buffer
&lt;ul&gt;
&lt;li&gt;buffer是一个内存块，与channel交互时使用，可以向其中写入数据并再次读取这些数据。&lt;/li&gt;
&lt;li&gt;buffer读写数据通常遵循以下步骤：1. 将数据写入buffer；2. 调用buffer.flip()切换读写模式；3. 从buffer中读取数据；4. 调用buffer.clear()重置buffer。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;选择器selector：selector可以检测多个Java channel实例，并确定哪些通道已准备好进行读取或写入。这样单个线程就可以管理多个通道，从而可以管理多个io连接，这种方式避免创建过多线程，减少资源占用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Netty&lt;/h3&gt;
&lt;p&gt;Netty是一个基于Java NIO的网络编程框架，提供了一套高效的、事件驱动的异步网络通信机制。Netty底层使用了Java的NIO基础，并在其基础上进行了性能的优化。&lt;/p&gt;
&lt;h2&gt;正则表达式&lt;/h2&gt;
&lt;h3&gt;实例1：入参格式校验&lt;/h3&gt;
&lt;p&gt;需求：校验入参是否为公司账号&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pattern：用于定义匹配模式&lt;/li&gt;
&lt;li&gt;Matcher：用于指定具体进行匹配方式&lt;/li&gt;
&lt;li&gt;matcher.matches()：整体匹配&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;public void match_entire() {
  String input = &quot;l50039872&quot;;
  String regex = &quot;[a-z]\\d{8}&quot;;
  boolean isMatch = Pattern.matches(regex, input);
  System.out.println(&quot;match entire: &quot; isMatch);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;实例2：字符串匹配搜索&lt;/h3&gt;
&lt;p&gt;需求：寻找报文中所有的公司账号&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;matcher.find()：是否找到匹配的子字符串&lt;/li&gt;
&lt;li&gt;matcher.group(0)：匹配的当前字符串&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;public void match_all() {
  String input = &quot;Java Engineer: l50039872, d23454582&quot;;
  String regex = &quot;[a-z]\\d{8}&quot;;
  Pattern p = Pattern.compile(regex);
  Matcher m = p.matcher(input);
  int i = 0;
  while (matcher.find()) {
    System.out.println(++i + &quot; Found: &quot; + m.group(0));
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;实例3：字符串匹配搜索并分组解析&lt;/h3&gt;
&lt;p&gt;需求：寻找报文中的所有公司账号，并分别展示字母和数字&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;matcher.group(i)：匹配到的子字符串的第i个部分&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;public void group_match() {
  String input = &quot;Java Engineer: l50039872, d23454582&quot;;
  String regex = &quot;([a-z])(\\d{8})&quot;;
  Pattern p = Pattern.compile(regex);
  Matcher m = p.matcher(input);
  int i = 0;
  while (matcher.find()) {
    i++;
    System.out.println(i + &quot; Found: &quot; + m.group(0));
    System.out.println(i + &quot; Found 1: &quot; + m.group(1));
    System.out.println(i + &quot; Found 2: &quot; + m.group(2));
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;实例4：报文中的敏感字段过滤&lt;/h3&gt;
&lt;p&gt;需求1：将json报文中的敏感字段替换成&lt;code&gt;***&lt;/code&gt;，如果key中含&quot;password&quot;，则认为对应的value为敏感字段。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;input.replaceAll(regex, &quot;$1***$3&quot;)：第一个入参只要被替换字符的模式，第二个时替换换后的内容。这里用到了外部反向引用分组。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;public void replace_pwd() {
  String input = &quot;xxxxxx&quot;;
  String regex = &quot;(\&quot;.*password.*\&quot;: \&quot;)(\\w*)(\&quot;)&quot;;
  String output = input.replaceAll(regex, &quot;$1***$3&quot;);
  System.out.println(&quot;output = &quot; + output);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需求2：如果input包含多个password，会导致贪婪。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;非贪婪模式：可以通过在量词后面添加一个问号来实现。如果要匹配尽可能少的字符，可以使用&quot;*?&quot;或&quot;+?&quot;或&quot;??&quot;等非贪婪量词。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;public void replace_pwd_all() {
  String input = &quot;xxxxxx&quot;;
  String regex = &quot;(\&quot;.*?password.*?\&quot;: \&quot;)(\\w*)(\&quot;)&quot;;
  String output = input.replaceAll(regex, &quot;$1***$3&quot;);
  System.out.println(&quot;output = &quot; + output);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;数据库应用编程&lt;/h2&gt;
&lt;h3&gt;JDBC编程&lt;/h3&gt;
&lt;p&gt;JDBC（Java DataBase Connectivity）是Java连接数据库操作的原生接口。JDBC也是软件开发人员入门数据库开发的必学和基础只是，便于我们了解数据库操作的基本机制和用法。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static void main(String[] args) throws Exception {
  Connection c = null;
  Statement s = null;
  ResultSet resSet = null;
  try {
    // 加载MySQL驱动程序
    // 反射方式加载jar包中的com.jdbc.Driver类
    // 执行静态代码块中的DriverManager.registerDriver(new Driver())进行注册
    Class.forName(&quot;com.mysql.cj.jdbc.Driver&quot;);
    // 建立数据库连接
    // Connection为数据库连接对象，url指定连接的路径，格式为&quot;jdbc:mysql://ip地址:端口号/数据库名称&quot;
    c = DriverManager.getConnection(url, user, pwd);
    s = c.createStatement();
    // 执行sql查询
    String sql = &quot;SELECT * FROM TABLE LIMIT 10&quot;;
    resSet = s.executeQuery(sql);
    while (resSet.next()) {
      System.out.println(resSet.getString(xxxColumnLabel));
    }
  } catch (xxxException e) {
    ...
  } finally {
    ...
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意：禁止直接使用外部数据来拼接sql语句，避免sql注入。&lt;/p&gt;
&lt;p&gt;JDBC有几个关键接口：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Driver：每个驱动类都必须实现的接口，java sql框架允许使用多个数据库驱动程序。每个驱动程序都应该提供一个实现Driver接口的类。&lt;/li&gt;
&lt;li&gt;DriverManager：用于注册Driver，并创建数据库连接。DriverManager将尝试加载它能找到的尽可能多的驱动程序，然后对应任何给定的连接请求，它将依次要求每个驱动程序尝试连接到目标url。&lt;/li&gt;
&lt;li&gt;Connection：与特定数据库进行连接（会话），在连接的上下文中可以执行sql语句并返回结果。&lt;/li&gt;
&lt;li&gt;Statement：用于向数据库发送sql语句&lt;/li&gt;
&lt;li&gt;ResultSet：用于代表sql语句的执行结果。ResultSet对象维护了一个指向表格数据行的游标，类似迭代器。调用ResultSet.next()等方法可以使游标指向具体的数据行，进行调用方法获取该行的数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;MyBatis编程&lt;/h3&gt;
&lt;p&gt;ORM（Object Relational Mapping）是一种思想，是插入在应用程序和jdbc之间的一个中间层，便捷的将应用中的对象与数据库的字段进行映射，简化java数据库应用开发。&lt;/p&gt;
&lt;p&gt;JPA（Java Persistence API）是Java持久化规范，是ORM框架的标准。&lt;/p&gt;
&lt;p&gt;Mybatis是一个业界流行的持久化框架，但不严格依照JPA规范，底层封装了JDBC，开发更简洁、灵活。&lt;/p&gt;
&lt;p&gt;基于MyBatis的Java应用开发内容包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据库安装创建&lt;/li&gt;
&lt;li&gt;数据库配置&lt;/li&gt;
&lt;li&gt;DAO层Mapper接口开发&lt;/li&gt;
&lt;li&gt;Mapper.xml映射文件开发&lt;/li&gt;
&lt;li&gt;业务代码调用Mapper接口&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;基于SpringBoot框架的数据库应用开发中，需要在application.yml配置文件中添加如下数据库配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;spring:
	datasource:
		name: root
		url: jdbc:xxx(url)
		username: root
		password: xxx
		type: # 数据库连接池
		driver-class-name: com.mysql.cj.jdbc.Driver # 数据库驱动的类名，同jdbc的url
		
mybatis:
	mapper-locations: classpath:com.xxx/*.xml # 配置mapper.xml路径
	type-aliases-package: com.xxx # 实体类存放位置
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DAO层Mapper接口可以基于&lt;code&gt;@Mapper&lt;/code&gt;注解实现，是java业务代码进行数据库操作的纽带。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Mapper
public interface UserMapper {
  List&amp;lt;User&amp;gt; queryUserInfo(@Param(&quot;name&quot;) final String name);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Mapper.xml映射文件开发。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mapper namespace=&quot;com.xxx.dao.UserMapper&quot;&lt;/code&gt;要与Mapper接口类名保持一致。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;select id=&quot;queryUserInfo&quot;&lt;/code&gt;要与Mapper接口的方法名保持一致。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#{name}&lt;/code&gt; 标识接口中的参数，名称要一一对应。使用&quot;#&quot;方式避免sql注入。&lt;/li&gt;
&lt;li&gt;通过定义resultMap标识复杂对象类型与数据库字段的对应关系。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;mapper namespace=&quot;com.xxx.dao.UserMapper&quot;&amp;gt;
  &amp;lt;resultMap type=&quot;com.xxx.model.User&quot; id=&quot;userMap&quot;&amp;gt;
    &amp;lt;result property=&quot;name&quot; column=&quot;name&quot;/&amp;gt;
    &amp;lt;result property=&quot;description&quot; column=&quot;description&quot;/&amp;gt;
  &amp;lt;/resultMap&amp;gt;
  &amp;lt;select id=&quot;queryUserInfo&quot; resultMap=&quot;userMap&quot;&amp;gt;
    select * from TBL_USER_INFO user where NAME = #{name}
  &amp;lt;/select&amp;gt;
&amp;lt;/mapper&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;业务代码中合适位置调用Mapper接口即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@RestController
public class UserService {
  @Autowired
  private UserMapper userMapper;
  
  @RequestMapping(&quot;/queryUserInfo&quot;)
  public List&amp;lt;User&amp;gt; queryUserInfo(@RequestParam(&quot;name&quot;) String name) {
    List&amp;lt;User&amp;gt; userList = userMapper.queryUserInfo(name);
    return userList;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;网络编程&lt;/h2&gt;
&lt;p&gt;在JDK的java.net包中，提供Socket等api，封装了网络通信的底层细节，支持tcp和udp协议的网络通信。&lt;/p&gt;
&lt;p&gt;套接字socket是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象，是一种实时、双向的通信方式，客户端和服务器之间建立持久连接，双方可以随时发送和接收数据。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;即时通讯：通过socket，可以在多个用户之间实现实时的文字、音频或视频通信。&lt;/li&gt;
&lt;li&gt;文件传输：可以使用socket在不同计算机之间传输文件（视频、图片），断点续传。&lt;/li&gt;
&lt;li&gt;远程控制：可通过socket在远程计算机上执行指令或操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;网络编程socket有一些关键的api：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;public ServerSocket(int port)&lt;/code&gt;创建一个ServerSocket对象，绑定到指定的端口。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;public Socket accept()&lt;/code&gt;侦听此套接字建立的连接并接受它。该方法会阻塞，直到建立连接。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;public Socket(String host, int port)&lt;/code&gt;创建流套接字并将其连接到指定主机上的指定ip和端口号。连接后服务端的accept()方法返回服务端的socket。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;public InputStream getInputStream()&lt;/code&gt;返回此套接字的输入流，用于读取/接收数据。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;public OutputStream getOutputStream()&lt;/code&gt;返回此套接字的输出流，用于写入/发送数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实际业务场景中经常使用REST和WebSocket进行网络编程。&lt;/p&gt;
&lt;p&gt;REST是一种常见的网络通信方式，是一套架构原则，使用http协议进行网络通信。REST遵循单向的请求-响应的通信模式，但服务器无法在需要时主动向客户端推送数据。REST非常适合哪些采用单向的请求-响应模式的场景，比如查看新闻网页、提交评论等，但不适合需要双方实时通信的应用，比如视频聊天、在线游戏等。&lt;/p&gt;
&lt;p&gt;WebSocket是一种基于tcp协议的应用层协议，通过http/https协议建立起一个双向通信的通道，可以在客户端和服务器之间实现实时的数据传输。WebSocket可以看作是Socket的一种高级应用，它在socket的基础上实现了更高层次的协议和更便捷的编程接口，使得开发者可以更方便地实现实时通信。&lt;/p&gt;
&lt;h2&gt;安全类库&lt;/h2&gt;
&lt;p&gt;运行未知地java程序时，可能触发代码中的不安全或敏感操作（删除系统文件、重启系统等）。为防止直接运行相关代码对系统产生负面影响，需要对相关操作权限进行控制。&lt;/p&gt;
&lt;p&gt;JDK中内置了SecurityManager安全管理器，允许程序在执行可能不安全或敏感的操作之前确定该操作是什么，以及是否在允许执行该操作的安全上下文中尝试该操作。&lt;/p&gt;
&lt;h2&gt;类加载器&lt;/h2&gt;
&lt;h3&gt;类生命周期&lt;/h3&gt;
&lt;p&gt;类的生命周期中，有7个阶段：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;加载：读取java类字节码并转化为方法区进行时的数据结构，创建一个代表该类的class对象。&lt;/li&gt;
&lt;li&gt;验证：验证字节码信息是否符合jvm规范，防止恶意代码攻击jvm。&lt;/li&gt;
&lt;li&gt;准备：为类的静态变量分配内存，并为静态变量赋初始值。不包含被final修饰的static变量，因为在编译时已经分配。&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;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;类加载器机制&lt;/h3&gt;
&lt;p&gt;java中有3个内置类加载器，分别复杂加载不同的类：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;启动类加载器（Bootstrap ClassLoader）&lt;/li&gt;
&lt;li&gt;扩展类加载器（Extension ClassLoader）&lt;/li&gt;
&lt;li&gt;应用程序类加载器（Application ClassLoader）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;双亲委派机制是指当一个类加载器收到类加载请求时，它会先将该请求委派给它的父类加载器取尝试加载。只有当父类加载器无法加载该类时，子类加载器才会尝试加载。&lt;/p&gt;
&lt;p&gt;双亲委派机制的优点有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;避免重复加载：通过委派给父类加载器，可以避免同一个类被多次加载，提高了加载效率。&lt;/li&gt;
&lt;li&gt;安全性：通过双亲委派机制，核心类库由根加载器加载，可以确保核心类库的安全性，防止恶意代码替换核心类。&lt;/li&gt;
&lt;li&gt;扩展性：开发人员可以自定义类加载器，实现特定的加载策略，从而扩展java的类加载机制。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;运行时数据区&lt;/h2&gt;
&lt;p&gt;运行时数据区分为如下几个部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;程序计数器&lt;/li&gt;
&lt;li&gt;虚拟机栈&lt;/li&gt;
&lt;li&gt;本地方法栈&lt;/li&gt;
&lt;li&gt;Java堆&lt;/li&gt;
&lt;li&gt;方法区&lt;/li&gt;
&lt;li&gt;运行时常量池&lt;/li&gt;
&lt;li&gt;直接内存&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;JVM内存配置参数&lt;/h3&gt;
&lt;p&gt;业务中需基于各内存分区的作用、业务场景需求合理配置参数。常用的jvm内存配置如下：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&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;&lt;code&gt;Xmx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;jvm可申请的最大堆内存，创建对象过多且无法自动回收易导致堆溢出。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Xms&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;jvm启动时申请的堆内存。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Xss&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;线程栈大小，默认1024kb，程序递归深度太深容易导致线程栈溢出。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MaxMetaspaceSize&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;最大元空间，用于限制本地内存分配给类元数据的大小。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MaxDirectMemorySize&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;直接内存大小，使用ByteBuffer.allocateDirect()等方式申请直接内存过多或清理不及时就溢出。当Direct ByteBuffer分配的堆外内存到达指定大小后，会触发full gc。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;垃圾回收机制GC&lt;/h2&gt;
&lt;p&gt;程序计数器、虚拟机栈、本地方法栈3个区域随线程而生，随线程而无，比较确定。但java堆和方法区则有着很显著的不确定性，所以垃圾回收器所关注的堆和方法区的内存回收问题。&lt;/p&gt;
&lt;h3&gt;垃圾识别算法&lt;/h3&gt;
&lt;h4&gt;引用计数算法&lt;/h4&gt;
&lt;p&gt;在对象中添加一个引用计数器，每当有一个地方引用它时，计数器值+1，当引用失效时，计数器-1。任何时刻计数器=0的对象就是不能再被使用的。&lt;/p&gt;
&lt;p&gt;但是引用计数算法存在问题：对象之间循环引用等例外情况需要考虑，必须配合大量额外处理才能保证正确地工作。&lt;/p&gt;
&lt;h4&gt;可达性分析法&lt;/h4&gt;
&lt;p&gt;从gc roots开始，根据引用关系向下搜索，如果某个对象到gc roots间没有任何引用链相连，则证明此对象是不可能再被使用的。可以被认为是gc roots的对象有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在虚拟机栈（栈帧中的本地变量表）中引用的对象&lt;/li&gt;
&lt;li&gt;在方法区中类静态属性引用的对象&lt;/li&gt;
&lt;li&gt;在方法区中常量引用的对象&lt;/li&gt;
&lt;li&gt;在本地方法栈中JNI引用的对象&lt;/li&gt;
&lt;li&gt;java虚拟机内部的引用&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;引用关系类型&lt;/h4&gt;
&lt;p&gt;强引用是指代码中普遍存在的类似&lt;code&gt;Object obj = new Object()&lt;/code&gt;之类的应用，只要强引用还存在，垃圾收集器永远不会回收被引用的对象。&lt;/p&gt;
&lt;p&gt;软引用&lt;code&gt;SortReference&lt;/code&gt;描述的是那些还有用但并非必须的对象。在系统将要发生内存溢出异常之前，将会把这些对象列进回收范围进行二次回收。如果这次回收还没有足够的内存，才会抛出内存溢出异常。&lt;/p&gt;
&lt;p&gt;弱引用&lt;code&gt;WeakReference&lt;/code&gt;描述的是非必须对象。被弱引用关联的对象只能生存到下一次垃圾回收之前，垃圾收集器工作之后，无论当前内存是否足够，都会回收掉只被弱引用关联的对象。&lt;/p&gt;
&lt;p&gt;虚引用&lt;code&gt;PhantomReference&lt;/code&gt;存在的唯一目的就是在这个对象被收集器回收时收到一个系统通知，被虚引用关联的对象，和其生存时间完全没关系。&lt;/p&gt;
&lt;h3&gt;垃圾回收算法&lt;/h3&gt;
&lt;h4&gt;标记-清除算法&lt;/h4&gt;
&lt;p&gt;分为标记和清楚两个阶段，首先标记出所有需要回收的对象，标记完成后统一回收所有被标记的对象。&lt;/p&gt;
&lt;p&gt;但是从效率的角度讲，标记和清除的效率都不高。从空间的角度讲，标记清除后会产生大量不连续的内存碎片。&lt;/p&gt;
&lt;h4&gt;标记-复制算法&lt;/h4&gt;
&lt;p&gt;将可用内存按照容量划分为大小相等的两块，每次只使用其中的一块。当这一块的内存用完后，就将还存活着的对象复制到另外一块上面，然后再把已经使用过的内存空间一次清理掉。&lt;/p&gt;
&lt;p&gt;不过内存缩小为原来的一半，代价太高。在对象存活率较高时就要进行较多的复制操作，效率将会降低。&lt;/p&gt;
&lt;h4&gt;标记-整理算法&lt;/h4&gt;
&lt;p&gt;标记过程与标记-此乃给出算法一样，但后续步骤为让所有存货的对象都向内存空间一端移动，然后直接清理掉边界以外的内存。&lt;/p&gt;
&lt;h4&gt;分代收集&lt;/h4&gt;
&lt;p&gt;垃圾收集方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;部分收集Partial GC：目标不是完整收集整个java堆的垃圾收集
&lt;ul&gt;
&lt;li&gt;新生代收集Minor GC&lt;/li&gt;
&lt;li&gt;老年代收集Major GC&lt;/li&gt;
&lt;li&gt;混合收集Mixed GC&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;整堆收集Full GC：收集整个java堆和方法区的垃圾收集&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;垃圾收集器&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;收集器&lt;/th&gt;
&lt;th&gt;串行or并行or并发&lt;/th&gt;
&lt;th&gt;分代&lt;/th&gt;
&lt;th&gt;算法&lt;/th&gt;
&lt;th&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;Serial&lt;/td&gt;
&lt;td&gt;串行&lt;/td&gt;
&lt;td&gt;新生代&lt;/td&gt;
&lt;td&gt;复制&lt;/td&gt;
&lt;td&gt;响应速度优先&lt;/td&gt;
&lt;td&gt;单cpu环境下的client模式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serial Old&lt;/td&gt;
&lt;td&gt;串行&lt;/td&gt;
&lt;td&gt;老年代&lt;/td&gt;
&lt;td&gt;标记-整理&lt;/td&gt;
&lt;td&gt;响应速度优先&lt;/td&gt;
&lt;td&gt;单cpu环境下的client模式，cms的后备方案&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ParNew&lt;/td&gt;
&lt;td&gt;并行&lt;/td&gt;
&lt;td&gt;新生代&lt;/td&gt;
&lt;td&gt;复制&lt;/td&gt;
&lt;td&gt;响应速度优先&lt;/td&gt;
&lt;td&gt;多cpu环境时在server模式下与cms配合&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;parallel scavenge&lt;/td&gt;
&lt;td&gt;并行&lt;/td&gt;
&lt;td&gt;新生代&lt;/td&gt;
&lt;td&gt;复制&lt;/td&gt;
&lt;td&gt;吞吐量优先&lt;/td&gt;
&lt;td&gt;在后台运算而不需要太多交互的任务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;parallel old&lt;/td&gt;
&lt;td&gt;并行&lt;/td&gt;
&lt;td&gt;老年代&lt;/td&gt;
&lt;td&gt;标记-整理&lt;/td&gt;
&lt;td&gt;吞吐量优先&lt;/td&gt;
&lt;td&gt;在后台运算而不需要太多交互的任务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cms&lt;/td&gt;
&lt;td&gt;并发&lt;/td&gt;
&lt;td&gt;老年代&lt;/td&gt;
&lt;td&gt;标记-清除&lt;/td&gt;
&lt;td&gt;响应速度优先&lt;/td&gt;
&lt;td&gt;集中在互联网站或b/s系统服务端上的java应用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;g1&lt;/td&gt;
&lt;td&gt;并发&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;标记-整理+复制&lt;/td&gt;
&lt;td&gt;响应速度优先&lt;/td&gt;
&lt;td&gt;面向服务端应用，将来替换cms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded></item><item><title>Java编程入门</title><link>https://lllirunze.cn/posts/huawei-chuying-4/</link><guid isPermaLink="true">https://lllirunze.cn/posts/huawei-chuying-4/</guid><description>基本数据类型在使用时，如果忽略取值范围，会造成代码异常。</description><pubDate>Fri, 25 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;基本数据类型&lt;/h2&gt;
&lt;p&gt;基本数据类型的占用空间固定，直接在变量中存储值和传递值。基本数据类型有byte, short, int, long, float, double, char, boolean。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基本数据类型在使用时，如果忽略取值范围，会造成代码异常&lt;/li&gt;
&lt;li&gt;浮点数不能直接用&lt;code&gt;==&lt;/code&gt;比较&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;char和String赋值时需要注意转义，尤其时八进制/十六进制表示方法。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&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;\b&lt;/td&gt;
&lt;td&gt;退格backspace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\f&lt;/td&gt;
&lt;td&gt;换页，将当前位置移到下页开头&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\n&lt;/td&gt;
&lt;td&gt;换行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\r&lt;/td&gt;
&lt;td&gt;回车&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\t&lt;/td&gt;
&lt;td&gt;水平制表，跳到下一个tab位置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\\&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;代表一个反斜线字符&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\&apos;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;代表一个单引号字符&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;代表一个双引号字符&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;空字符null&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1到3位八进制数所代表的任意字符&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\u0000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unicode转义字符，\u + 4个十六进制数字，&lt;code&gt;\u0000&lt;/code&gt;表示空字符&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;基本数据类型存在以下类型转换：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;自动类型转换&lt;/li&gt;
&lt;li&gt;强制类型转换&lt;/li&gt;
&lt;li&gt;类型提升&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;java所有的数值类型之间可以相互转换。如果系统可以把一种类型的值赋给另一种类型，称为自动类型转换。允许自动类型转换的标准是表数范围小的类型赋值给表数范围大的类型。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从整数型向浮点型转换时，仍可能有精度损失。&lt;/li&gt;
&lt;li&gt;如果转换和计算同时进行，要小心数据的溢出。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;强制类型转换可用于所有基础数值类型之间的转换，很多场合特指表数范围大的类型给表数范围小的类型赋值。&lt;/p&gt;
&lt;p&gt;类型提升指的是当一个算数表达式包含多个基本类型的值时，整个算术表达式的数据类型将发生自动提升。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;byte、char、short自动提升为int&lt;/li&gt;
&lt;li&gt;整个表达式的数据类型自动提升至表达式中的最高数据类型&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;引用数据类型&lt;/h2&gt;
&lt;p&gt;引用数据类型类似于c的指针，存放的是对象的引用。引用变量在声明时被指定为一个特定的类型，一旦声明后，类型就不能被改变。&lt;/p&gt;
&lt;p&gt;引用类型包括：类、接口、数组、枚举和注解。默认值为null。引用变量可以用来引用任何与之兼容的类型。&lt;/p&gt;
&lt;h3&gt;数组&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// 声明
int array[];
int[] array;
// 初始化
int[] array = new int[5];
int[] array = {0, 1, 2};
int[] array = new int[]{0, 1, 4};
// 错误的示例
int array[5];
int array[5] = {0, 1, 2, 3, 4};
// 索引遍历
for (int i=0; i&amp;lt;array.length; i++) {}
// for-each遍历
for (int value : array) {}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;包装类&lt;/h3&gt;
&lt;p&gt;包装类就是把基本数据类型和其辅助方法封装到类中，注意基本类型不是类，无法获得类的基本特性（无法参与转型、泛型、集合、反射等过程）。用包装类就是为了弥补这个缺陷。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Integer a = Integer.valueOf(5); // 装箱
int b = a.intValue(); // 拆箱
Integer a = 5; // 自动装箱
int b = a; // 自动拆箱
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;由于包装类的拆装箱过于无感，混用时可能造成性能问题&lt;/li&gt;
&lt;li&gt;当引用数据类型有更匹配的重载方法时，不会自动拆装箱&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;包装类比较必须使用&lt;code&gt;equals()&lt;/code&gt; ，&lt;code&gt;==&lt;/code&gt;比较的是两个引用是否指向一个对象。&lt;/p&gt;
&lt;p&gt;包装类的创建很浪费性能，因此java对简单数字(-128~127)对应的包装类进行了缓存，称为常量池。通过直接量赋值的包装类如果在此范围内，会直接使用常量池的引用，因此&lt;code&gt;==&lt;/code&gt;返回true。&lt;/p&gt;
&lt;p&gt;包装类默认值为null，自动拆箱时会报NullPointerException。&lt;/p&gt;
&lt;h2&gt;Java基本语法&lt;/h2&gt;
&lt;p&gt;java的程序结构由不同的包组成，包由java文件组成，每个java文件有且只能有一个和文件同名的公共类/接口。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;包声明：每个文件至多一句，声明类所在的包&lt;/li&gt;
&lt;li&gt;import声明：文件中引入的所有外部类声明&lt;/li&gt;
&lt;li&gt;公共类/接口：每个文件只能有一个公共类，类名必须和文件名一致。所有的内部类、成员、方法等都写在公共类内&lt;/li&gt;
&lt;li&gt;程序入口：java程序的入口方法，形式必须为&lt;code&gt;public static void main (String[] args)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;package com.example.myapp; // 包声明

import java.util.ArrayList; // import声明
import java.util.List;

public class MyClass{ // 公共类
  private List mList = new ArrayList();
  public static void main (String[] args) { // 程序入口
  
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;标志符：在java语言中，用来标志类名、对象名、变量名、方法名、类型名、数组名、包名的有效字符序列，称为标志符。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;由子母、数字、下划线、$组成，且第一个字符不能是数字&lt;/li&gt;
&lt;li&gt;区分大小写&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关键字：有一些专门词汇被赋予特殊含义，不能作为标志符。&lt;/p&gt;
&lt;p&gt;运算符：&lt;/p&gt;
&lt;ul&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;li&gt;赋值运算符&lt;/li&gt;
&lt;li&gt;条件运算符&lt;/li&gt;
&lt;li&gt;instanceof 运算符&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;逻辑与流程控制：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;循环结构：for、while、do...while&lt;/li&gt;
&lt;li&gt;条件语句：if...else、switch(尽量不要省略break)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;异常处理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;检查性异常：用户错误或问题引起的异常，是程序员无法预见的&lt;/li&gt;
&lt;li&gt;运行时异常：可能被程序员避免的异常，在编译时可以被忽略&lt;/li&gt;
&lt;li&gt;错误：错误不是异常，而是脱离程序员控制的问题。错误在代码中通常被忽略&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;try {
  // 用于监听，将要被监听的代码放在里面，当try语句块内发生异常时，异常就被抛出
} catch (NullPointerException e) {
  // 捕获异常
} catch (Exception e) {
  
} finally {
  // finally语句块总是会被执行。它主要用于回收在try块里打开的物力资源。只有finally块，执行完成之后，才会回来执行try或者catch块中的return或者throw语句。如果finally块中使用了return或者throw，则不会跳回执行，直接停止
}

// throw用于抛出异常
// throws用在方法签名中，用于声明该方法可能抛出的异常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;异常匹配规则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果抛出的异常对象属于catch子句中的异常类，或者属于该异常类的子类，则认为生成的异常对象与catch块捕获的异常类型相匹配。&lt;/li&gt;
&lt;li&gt;每个catch子句依次检查，一旦有子句匹配，则后面的被旁路。因此编写多重catch语句时，需要先小后大，即先子类再父类。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;finally规则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;finally语句必定会执行，除非程序/线程提前退出。&lt;/li&gt;
&lt;li&gt;finally执行时机再try/catch代码块退出前，即所有代码块后，跳出逻辑前。&lt;/li&gt;
&lt;li&gt;finally执行语句不会影响原有返回值。&lt;/li&gt;
&lt;li&gt;finally中如果执行return或抛异常，会代替原有返回逻辑。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Lambda表达式&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;new Thread { // 省略了接口名、函数名，注意行末没有分号
  () -&amp;gt; System.out.println(&quot;Thread&quot;)
}

List&amp;lt;String&amp;gt; list = Arrays.&amp;lt;String&amp;gt;.asList(&quot;Lambda&quot;, &quot;is&quot;, &quot;wonderful&quot;);
Collections.sort(list, (s1, s2) -&amp;gt; { // s1, s2省略了参数表类型，直接写形参。多行代码用{}包围
  if (s1 == null) return -1;
  if (s2 == null) return 1;
  return s1.length() - s2.length();
})
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Lambda只能用在函数接口上，即只含有一个方法的接口&lt;/li&gt;
&lt;li&gt;Lambda依赖于参数推断&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;IO编程&lt;/h2&gt;
&lt;p&gt;在java io中，流是一个核心的概念。流从概念上说是一个连续的数据流。你既可以从流中读取数据，也可以往流中写数据。流与数据源或者数据流向的媒介相关联。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;字节流：以字节byte为单位处理数据，适合处理二进制数据 InputStream, OutputStream&lt;/li&gt;
&lt;li&gt;字符流：以Unicode码元（char）为单位处理数据，适合处理文本数据 Reader, Writer&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;NIO（Non-blocking I/O）是一种同步非阻塞的io模型，也是io多路复用的基础，成为解决高并发与大量连接、io处理问题的有效方式。nio不同于io的一点在于nio面向缓冲区，而io面向流。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;buffer缓冲区：一块可读写数据的内存。java中包装为Buffer对象，并提供了一组操作方法。buffer的读写步骤为：
&lt;ul&gt;
&lt;li&gt;1、写入数据到buffer&lt;/li&gt;
&lt;li&gt;2、flip()切换读模式&lt;/li&gt;
&lt;li&gt;3、从buffer中读取数据&lt;/li&gt;
&lt;li&gt;4、clear()/compact()方法清数据&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;channel通道：类似于流，但是有区别。
&lt;ul&gt;
&lt;li&gt;通道是双向的，可读也可写&lt;/li&gt;
&lt;li&gt;通道可以异步地读写&lt;/li&gt;
&lt;li&gt;通道中的数据总是要先读到一个buffer，或者总是要从一个buffer中写入&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;selector选择器：用于侦听多个通道是否已做好读写准备，配合nio实现单个线程管理多个通道。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;io多路复用是单个线程进行多个通道的io。&lt;/p&gt;
&lt;p&gt;阻塞io，非阻塞io和io多路复用的比较：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在阻塞io中，线程只能空闲等待，只有靠增加线程数提升效率。&lt;/li&gt;
&lt;li&gt;非阻塞io中，虽然可以同时尝试多个通道，但轮询会消耗过多cpu或者错过io时机。&lt;/li&gt;
&lt;li&gt;多路复用是触发式io，可以实现单线程管理多个通道，且不必担心错过读写时机。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;正则表达式&lt;/h2&gt;
&lt;p&gt;正则表达式定义了字符串的模式，可以用来搜索、编辑或者处理文本。正则表达式并不仅限于某一种语言，但是在每种语言中又细微的差别。&lt;/p&gt;
&lt;p&gt;在java中，&lt;code&gt;\\&lt;/code&gt;表示插入一个正则表达式的反斜线。在java中需要2个反斜杠才能被解析为其他语言中的转义作用。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&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;&lt;code&gt;^&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;匹配输入字符串开始的位置。如果设置了RegExp对象的Multiline属性，&lt;code&gt;^&lt;/code&gt;还会与\n和\r之后的位置匹配。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;匹配输入字符串结尾的位置。如果设置了RegExp对象的Multiline属性，&lt;code&gt;^&lt;/code&gt;还会与\n和\r之后的位置匹配。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;零次或多次匹配前面的字符或者子表达式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;+&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;一次或多次匹配前面的字符或者子表达式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;?&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;零次或一次匹配前面的字符或者子表达式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[a-z]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;字符范围，匹配指定范围内的任何字符&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\w&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;匹配任何字类字符，包括下划线&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\W&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;与任何非单词字符匹配&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code&gt;// 正则匹配
String content = &quot;XXXX&quot;;
String pattern = &quot;.*Huawei.*&quot;;
boolean isMatch = Pattern.matches(pattern, content);
System.out.println(isMatch);

// 捕获组
String line = &quot;This order was placed for xxxx&quot;;
String pattern = &quot;(\\D*)(\\d+)(.*)&quot;;
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(line);
if (m.find()) {
  System.out.println(&quot;Found Value: &quot; + m.group(0));
  System.out.println(&quot;Found Value: &quot; + m.group(1));
  System.out.println(&quot;Found Value: &quot; + m.group(2));
  System.out.println(&quot;Found Value: &quot; + m.group(3));
} else {
  System.out.println(&quot;No Match&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;正则注入regex injection：攻击者可能会通过恶意构造的输入对初始化的正则表达式进行修改，比如导致正则表达式不符合程序规定要求；可能会影响控制流，导致信息泄露，或导致ReDos攻击。java安全规范规定，禁止直接使用不可信数据构造正则表达式。利用方式有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;匹配标志：不可信的输入可能覆盖匹配选项，然后有可能会被传给Pattern.compile()方法。&lt;/li&gt;
&lt;li&gt;贪婪：一个非受信的输入可能试图注入一个正则表达式，通过它来改变初始的那个正则表达式，从而匹配尽可能多的字符串，从而暴露敏感信息。&lt;/li&gt;
&lt;li&gt;分组：程序员会用括号包括一部分的正则表达式以完成一组动作中某些共同的部分。攻击者通过提供非受信的输入来改变这种分组。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;针对正则注入的输入校验：&lt;/p&gt;
&lt;ul&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;/ul&gt;
&lt;h2&gt;面向对象&lt;/h2&gt;
&lt;p&gt;面向对象是在分析问题时，以问题所涉及到的事或物为中心的分析方式。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;类class表示归纳和整理&lt;/li&gt;
&lt;li&gt;对象object表示具体的事物&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;基本语法&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// 类的语法基本结构
/*
class 类名 {
  特征（属性）
  功能（方法）
}
*/

// 创建对象
// new 类名();

class Cooking {
  // 属性
  String name;
  String type = &quot;红烧&quot;;
  String food;
  String relish = &quot;大料&quot;;
  // 方法
  void execute() {
    System.out.println(&quot;准备食材:&quot; + food);
    System.out.println(&quot;准备佐料:&quot; + relish);
    System.out.println(&quot;开始烹饪&quot;);
    System.out.println(&quot;烹饪完成&quot;);
  }
}

public class Java_Object {
  public static void main(String[] args) {
    Cooking c = new Cooking();
    c.name = &quot;红烧排骨&quot;;
    c.food = &quot;排骨&quot;;
    c.execute();
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;类和对象&lt;/h3&gt;
&lt;p&gt;类是一种结构体，里面包含了属性和方法，会有很多的对象。&lt;/p&gt;
&lt;p&gt;对象是类的实例化，一般new出来的对象会赋值给变量，方便重复使用。变量的类型就是对象的类型。对象是将内存地址赋值给了变量，所以变量其实引用了内存中的对象，所以称之为引用变量，而变量的类型称之为引用数据类型。&lt;/p&gt;
&lt;p&gt;有一种特殊的对象null。null是没有引用的对象，称为空对象。所有引用类型变量的默认取值是null。&lt;/p&gt;
&lt;h3&gt;静态&lt;/h3&gt;
&lt;p&gt;把和对象无关，只和类相关的称之为静态static。和类相关的属性称之为静态属性，和类相关的方法称之为静态方法。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Test {
  String name;
  static String sex;
  void test() {
    test1(); // 成员方法可以访问静态属性和静态方法，因为对象先于类存在
    System.out.println(&quot;test...&quot;);
  }
  static {
    // 对象准备创建时，也会自动调用代码块，但不是静态的
    System.out.println(&quot;静态代码块执行&quot;); // 类的信息加载完成后，会自动调用静态代码块，可以完成静态属性的初始化功能
  }
  static void test1() {
    System.out.println(&quot;test1...&quot;);
  }
}

public class Java_Static {
  public static void main(String[] args) {
    Test t = new Test();
    t.test();
    t.test1();
    Test.test1(); // 两种都可以
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;构造方法&lt;/h3&gt;
&lt;p&gt;构造方法专门用于构造对象。如果一个类中没有任何的构造方法，那么JVM会自动添加一个公共的、无参的构造方法，方便对象的调用。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;构造方法也是方法，但是没有void关键字&lt;/li&gt;
&lt;li&gt;方法名和类名相同&lt;/li&gt;
&lt;li&gt;如果类中没有构造方法，那么JVM会提供默认的构造方法&lt;/li&gt;
&lt;li&gt;构造方法也是方法，所以也可以传递参数，但是一般传递参数的目的是用于对象属性的赋值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;class User {
  String username;
  User(String name) {
    username = name;
    System.out.println(&quot;Name: &quot; + name);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;继承&lt;/h3&gt;
&lt;p&gt;类的继承只能单继承，一个类只能有一个父类，不能存在多个父类。继承采用extends语法。&lt;/p&gt;
&lt;p&gt;父类对象是在子类对象创建前创建完成，创建子类对象前，会调用父类的构造方法完成父类的构建。默认情况下，子类对象构建时，会默认调用父类的构造方法完成父类对象的构建，使用的时super()的方式，只不过JVM自动完成。如果父类提供构造方法，那么JVM不会提供默认的构造方法，那么子类应该显示调用super方法构建父类对象。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Parent {
  String name = &quot;zhangsan&quot;;
	void test() { System.out.println(&quot;test...&quot;); }
  Parent() { System.out.println(&quot;parent...&quot;); }
}

class Child extends Parent {
  Child() {
    super();
    System.out.println(&quot;child...&quot;);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;多态&lt;/h3&gt;
&lt;p&gt;多态是一个对象在不同场景下表现出来的不同状态和形态。多态语法是对对象的使用场景进行了约束。一个对象可以使用的功能取决于引用变量的类型。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Person {
  void testPerson() { System.out.println(&quot;test person...&quot;); }
}

class Boy extends Person {
  void testBoy() { System.out.println(&quot;test boy...&quot;); }
}

public class Java_Polymorphism {
  public static void main(String[] args) {
    Person p = new Person();
    p.testPerson();
    Person p1 = new Boy();
    // p1.testBoy(); 无法运行
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;重载与重写&lt;/h3&gt;
&lt;p&gt;一个类中，不能重复声明相同的方法，也不能声明相同的属性。这里相同的方法指的是方法名，参数列表相同，和返回值类型无关。&lt;/p&gt;
&lt;p&gt;如果方法名相同，但是参数列表（个数，顺序，类型）不同，会认为是不同的方法，只不过名称一样，这个操作在Java称之为方法的重载。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class User {
  User() {}
  User(String name) { System.out.println(&quot;name: &quot; + name); }
  
  void login(String account, String pwd) { System.out.println(&quot;登录&quot;); }
  void login(int tel) { System.out.println(&quot;手机验证码登录&quot;); }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;父类对象的方法主要体现通用性，无法在特殊的场合下使用。如果子类对象需要在特殊的场合下使用，那么就需要重写方法的逻辑，这个操作在Java中称之为方法的重写。这里的重写，并不意味着父类的方法被覆盖掉，只是在当前的场合不使用，如果使用的话可以使用super关键字访问。&lt;/p&gt;
&lt;p&gt;方法的重写要求子类的方法和父类的方法名相同，返回值类型相同，参数列表相同&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Parent {
  String name = &quot;zhangsan&quot;;
  void test() { System.out.println(&quot;parent test...&quot;); }
}

class Child {
  String name = &quot;lisi&quot;;
  void test() {
    super.test();
    System.out.println(&quot;child test...&quot;);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;访问权限&lt;/h3&gt;
&lt;p&gt;Java中的访问权限主要分为四种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;private：同一个类中可以使用&lt;/li&gt;
&lt;li&gt;default：默认权限，当不设定任何权限时，JVM会默认提供权限，包（路径）权限&lt;/li&gt;
&lt;li&gt;protected：受保护的权限，子类可以访问&lt;/li&gt;
&lt;li&gt;public：任意使用&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;内部类&lt;/h3&gt;
&lt;p&gt;所谓的外部类就是在源码中直接声明的类，而内部类则是类中声明的类。&lt;/p&gt;
&lt;p&gt;Java不允许外部类使用private，protected修饰，内部类就当成外部类的属性使用即可。因为内部类可以看作外部类的睡醒，所以需要构建外部类对象才可以使用。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class Java_InnerClass {
  public static void main(String[] args) {
    OuterClass outer = new OuterClass();
    OuterClass.InnerClass inner = outer.new InnerClass();
  }
}

class OuterClass {
  public class InnerClass {
    
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;final&lt;/h3&gt;
&lt;p&gt;Java中提供了一种语法，可以在数据初始化后不被修改，使用关键字final。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;final可以修饰变量，变量的值一旦初始化无法被修改。一般将final修饰的变量称之为常量，或者叫不可变变量。&lt;/li&gt;
&lt;li&gt;final可以修饰属性，那么JVM无法自动进行初始化，需要自己进行初始化，属性值不能发生变化。&lt;/li&gt;
&lt;li&gt;final可以修饰方法，这个方法不能被子类重写。&lt;/li&gt;
&lt;li&gt;final可以修饰类，这个类就没有子类。&lt;/li&gt;
&lt;li&gt;final不可以修饰构造方法。&lt;/li&gt;
&lt;li&gt;final可以修饰方法的参数，一旦修饰，参数就无法修改。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;final String name = &quot;zhangsan&quot;;

class User {
  public final String name;
  public User(String name) {
    this.name = name;
  }
  public final void test() {}
}

final class FinalClass {
  public FinalClass() {}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;抽象&lt;/h3&gt;
&lt;p&gt;抽象方法是只有声明，但是没有实现的方法。抽象类是不完整的类，因为类不完整，所以无法构建对象。&lt;/p&gt;
&lt;p&gt;如果一个类中含有抽象方法，那么这个类就是抽象类；如果一个类是抽象类，它的方法不一定是抽象方法。&lt;/p&gt;
&lt;p&gt;抽象类无法直接构建对象，但是可以通过子类间接构建对象。如果抽象类中含有抽象方法，需要重写抽象方法，将方法补充完整。&lt;/p&gt;
&lt;p&gt;abstract关键字不能和final同时使用。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;abstract class Parent {
  public abstract void eat();
  public void test() {}
}

class Child extends Parent {
  public void eat() {
    System.out.println(&quot;eat...&quot;);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;接口&lt;/h3&gt;
&lt;p&gt;接口可以简单理解为规则，是抽象的。规则的属性必须为固定值，而且不能修改，属性和行为的访问权限必须为公共的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;属性应该是静态的。&lt;/li&gt;
&lt;li&gt;行为应该是抽象的。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;接口和类是两个层面的东西，接口可以继承其他接口，类的对象需要遵循接口，在Java中这个遵循，称之为实现，类需要实现接口，而且可以实现多个接口。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;interface USBInterface {}
interface USBSupply extends USBInterface {
  public void powerSupply();
}
interface USBReceive extends USBInterface {
  public void powerReceive();
}

class Computer implements USBSupply {
  public USBReceive usb1;
  public USBReceive usb2;
  public void powerSupply() {
    System.out.println(&quot;电脑提供能源...&quot;);
    usb1.powerReceive();
    usb2.powerReceive();
  }
}

class Light implements USBReceive {
  public void powerReceive() {
    System.out.println(&quot;电灯接收能源...&quot;);
  }
}

public class Java_Interface {
  public static void main(String[] args) {
    Computer c = new Computer();
    Light l1 = new Light();
    c.usb1 = l1;
    Light l2 = new Light();
    c.usb2 = l2;
    c.powerSupply();
  }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>编程后台操作</title><link>https://lllirunze.cn/posts/huawei-chuying-3/</link><guid isPermaLink="true">https://lllirunze.cn/posts/huawei-chuying-3/</guid><description>作为系统管理员，我们需要监控哪些项目？</description><pubDate>Mon, 14 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;数据库&lt;/h2&gt;
&lt;p&gt;数据库database(DB)：以一定方式储存在一起，能为多个用户共享、具有尽可能小的冗余度、与应用数据彼此独立的数据集合，它具有完整性、共享性&lt;/p&gt;
&lt;p&gt;数据库管理系统database management system(DBMS)：一种操纵和管理数据库的大型文件，用于建立、使用和维护数据库。它对db进行统一的管理和控制，以保证db的安全性、完整性、共享性等。&lt;/p&gt;
&lt;h3&gt;数据存储管理的发展阶段&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;人工管理：数据保存在磁带上，只能顺序读写、不能共享、数据冗余、一致性差&lt;/li&gt;
&lt;li&gt;文件系统：数据以文件形式存储在磁盘上，应用程序和数据访问相对独立，无集中管理，数据冗余&lt;/li&gt;
&lt;li&gt;数据库：结构化数据模型，数据和程序彼此独立，冗余度低，数据控制功能&lt;/li&gt;
&lt;li&gt;大数据：数据量大，分布式计算，Hadoop，NoSQL&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;关系型数据库&lt;/h3&gt;
&lt;p&gt;关系型db是建立在关系模型基础上的db，借助于集合代数等数学概念和方法来处理db中的数据。&lt;/p&gt;
&lt;p&gt;各种实体和实体之间的联系用关系模型表示。&lt;/p&gt;
&lt;p&gt;标准数据查询语言SQL是一种基于关系数据库的语言，这种语言执行对关系数据库中的数据的检索和操作。&lt;/p&gt;
&lt;h2&gt;SQL&lt;/h2&gt;
&lt;p&gt;结构化查询语言Structured Query Language(SQL)一些基本概念：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;投影：选出列&lt;/li&gt;
&lt;li&gt;选择：选出行&lt;/li&gt;
&lt;li&gt;连接：从一张或多张表中选择出合适的行再进行查询&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;学习路线：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1EJ411p7Ty&quot;&gt;Mysql下载安装和配置方法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.runoob.com/sql/sql-tutorial.html&quot;&gt;SQL 教程 | 菜鸟教程&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;select查询语句基础&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;select * | {[distinct] column | expression[alias],...} from table; # select基本语句
select column as another_name from table; # 重命名列标题
select col1, col2, col1||col2 as &quot;Employees&quot; from table; # 级联操作是将列或者字符串和其他列串联，用||表示
select distinct column from table; # 消除重复行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;NULL值是不可用且未分配，未知并且不适用的值。&lt;/p&gt;
&lt;h3&gt;查询数据的限制与排序&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;select * | {[distinct] column | expression[alias],...}
from table
[where conditions] # 限制选择的行
[order by col1 [asc|desc], col2 [asc|desc], ...] # 按照某列排序，从左到右按序排序，默认升序
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运算符：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&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;=&lt;/td&gt;
&lt;td&gt;等于&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;gt;&lt;/td&gt;
&lt;td&gt;大于&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;gt;=&lt;/td&gt;
&lt;td&gt;大于等于&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt;&lt;/td&gt;
&lt;td&gt;小于&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt;=&lt;/td&gt;
&lt;td&gt;小于等于&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt;&amp;gt;&lt;/td&gt;
&lt;td&gt;不等于&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;between ... and ...&lt;/td&gt;
&lt;td&gt;在...和...之间（闭区间）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;in (set)&lt;/td&gt;
&lt;td&gt;匹配任意一个值&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;like&lt;/td&gt;
&lt;td&gt;模糊匹配（&apos;%&apos;通配0个或多个字符，&apos;_&apos;通配一个字符）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;is NULL&lt;/td&gt;
&lt;td&gt;是一个NULL值&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;and&lt;/td&gt;
&lt;td&gt;与&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;or&lt;/td&gt;
&lt;td&gt;或&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;not&lt;/td&gt;
&lt;td&gt;非&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;lower(&apos;xxx&apos;)&lt;/td&gt;
&lt;td&gt;转小写&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;upper(&apos;xxx&apos;)&lt;/td&gt;
&lt;td&gt;转大写&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;initcap(&apos;xxx&apos;)&lt;/td&gt;
&lt;td&gt;单词首字母转大写&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;concat(&apos;xxx&apos;, &apos;xxx&apos;)&lt;/td&gt;
&lt;td&gt;字符连接&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;substr(&apos;xxx&apos;, 1, 2)&lt;/td&gt;
&lt;td&gt;取子串（从第一个字符选取，选取2位）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;length(&apos;xxx&apos;)&lt;/td&gt;
&lt;td&gt;取字符串长度&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;instr(&apos;xxx&apos;, &apos;str&apos;)&lt;/td&gt;
&lt;td&gt;返回子字符串在字符串中的位置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;round(num, 2)&lt;/td&gt;
&lt;td&gt;小数点后2位四舍五入&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;trunc(num, 2)&lt;/td&gt;
&lt;td&gt;把小数点后两位保留，剩下截掉&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sysdate&lt;/td&gt;
&lt;td&gt;反馈系统当前日期&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;to_number()&lt;/td&gt;
&lt;td&gt;字符转数字&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;to_char()&lt;/td&gt;
&lt;td&gt;数字/日期转字符&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;to_date()&lt;/td&gt;
&lt;td&gt;字符转日期&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;avg(num)&lt;/td&gt;
&lt;td&gt;返回数字表达式中所有值的平均值&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sum(num)&lt;/td&gt;
&lt;td&gt;返回数字表达式或列总和&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;count(*)&lt;/td&gt;
&lt;td&gt;返回表达式中值的个数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;max(num)&lt;/td&gt;
&lt;td&gt;返回表达式中值的最大值&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;min(num)&lt;/td&gt;
&lt;td&gt;返回表达式中值的最小值&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code&gt;select col1, avg(col2)
from table
group by col1; # 按照col1分组，在每组中计算平均值

select col1, max(col2)
from table
group by col1
having max(col2) &amp;gt; 10000; # 根据分组后的查询结果进行筛选显示，having只能写在group by后面
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;多表查询&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;自连接：一个表自己与自己建立连接&lt;/li&gt;
&lt;li&gt;等值连接：查询两个表，用where进行col的等值匹配&lt;/li&gt;
&lt;li&gt;左外连接：优先连接左表，左表如果无法连接到，则保留为空&lt;/li&gt;
&lt;li&gt;右外连接：优先连接右表，右表如果无法连接到，则保留为空&lt;/li&gt;
&lt;li&gt;全连接：显示所有记录，如果两边无法连接到，都保留为空&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;# 等值连接
select emp.ename, emp.job, dept.deptno, dept.dname
from emp, dept
where emp.deptno=dept.deptno;

# 左外连接（优先连emp表）
select emp.ename, emp.job, dept.deptno, dept.dname
from emp, dept
where emp.deptno=dept.deptno(+);

# 全连接
select emp.ename, emp.job, dept.deptno, dept.dname
from emp full join dept
on emp.deptno=dept.deptno;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;in&lt;/td&gt;
&lt;td&gt;等于列表中的任何一个&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;any&lt;/td&gt;
&lt;td&gt;和子查询返回的任意一个值比较&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;all&lt;/td&gt;
&lt;td&gt;和子查询返回的所有值比较&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code&gt;select select_list
from table
where expr operator # 主查询
	(select select_list
  from table
  where condition); # 子查询
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意一下几点：&lt;/p&gt;
&lt;ul&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;li&gt;对多行子查询使用多行运算符&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;表结构操作语句&lt;/h3&gt;
&lt;p&gt;表时数据库存储结构的逻辑概念，表分为行和列。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;create table [USER.] table_name (
  {col1 datatype [column_constraint][table_constraint]}
  {col2 datatype [column_constraint][table_constraint]}
  {...}
); # 创建表格（列名称，列数据类型，列约束，表约束）
drop table table_name cascade constraints; # 删除内容和定义，释放空间
describe table_name # 查看表结构

alter table table_name add column_name datatype; # 增加列
alter table table_name drop column column_name;  # 删除列
alter table table_name rename to new_table_name; # 修改表名
alter table table_name rename column col_name to new_col_name; # 修改列名
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&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;varchar2(L)&lt;/td&gt;
&lt;td&gt;可变长度字符串&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;date&lt;/td&gt;
&lt;td&gt;日期数据类型（日-月-年）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;number(p, s)&lt;/td&gt;
&lt;td&gt;数字类型（p为整数位，s为小数位）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;布尔类型，只有true，false和null&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&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;not null&lt;/td&gt;
&lt;td&gt;非空&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;unique&lt;/td&gt;
&lt;td&gt;唯一&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;primary key&lt;/td&gt;
&lt;td&gt;主键&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;foreign key&lt;/td&gt;
&lt;td&gt;外键&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;条件检查&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&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;unique&lt;/td&gt;
&lt;td&gt;唯一&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;primary key&lt;/td&gt;
&lt;td&gt;主键&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;foreign key&lt;/td&gt;
&lt;td&gt;外键&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;条件检查&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;数据操作语句&lt;/h3&gt;
&lt;p&gt;数据操作语言DML是SQL语言的核心部分，当你做下列操作时DML语句会被执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;insert into table[(column [, column, ...])]
values (value (, value, ...)); # 增加新行到表中

update table
set column=value [, column=value, ...]
[where condition]; # 修改表中的行

delete [from] table
[where condition]; # 删除表中的行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;insert：
&lt;ul&gt;
&lt;li&gt;该语句一次只能插入一行到表中&lt;/li&gt;
&lt;li&gt;插入新的一行，每列都包含值&lt;/li&gt;
&lt;li&gt;按照表中列的默认顺序列除数值&lt;/li&gt;
&lt;li&gt;在insert子句中列出列是可选的&lt;/li&gt;
&lt;li&gt;将日期和字符数值放入单引号中&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;update，delete：
&lt;ul&gt;
&lt;li&gt;使用where会指定要修改的行&lt;/li&gt;
&lt;li&gt;不使用where会修改所有的行&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;事务操作语句&lt;/h3&gt;
&lt;p&gt;事务可以看作是由对db的若干操作组成的一个单元，要么全完成，要么全取消，保证数据满足一致性的要求。&lt;/p&gt;
&lt;p&gt;事务开始于第一个dml的sql语句执行时，结束与下列事件之一：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;发出commit或者rollback语句&lt;/li&gt;
&lt;li&gt;一个数据定义语言ddl或数据控制语言dcl语句执行（隐式提交）&lt;/li&gt;
&lt;li&gt;用户退出iSQL*Plus（默认提交）&lt;/li&gt;
&lt;li&gt;系统崩溃（隐式提交）&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&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;commit&lt;/td&gt;
&lt;td&gt;提交事务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;roll back&lt;/td&gt;
&lt;td&gt;回滚事务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;savepoint&lt;/td&gt;
&lt;td&gt;事务的标记点，可以使一个事务再回滚到不同的阶段&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;roll back to &amp;lt;savepoint&amp;gt;&lt;/td&gt;
&lt;td&gt;与savepoint对应，回滚到标记点&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;commit命令执行之前，dcl首先影响db缓冲区，因此，数据以前的状态可以被恢复；当前用户可以查询表观察到dcl的结果；其他用户不能观察到当前所作的dcl的结果；其他用户不能改变受影响的行中的数据。&lt;/p&gt;
&lt;p&gt;commit执行之后，数据在db中被永久的改变，数据以前的状态永久丢失；所有用户都可以观察到事务的结果；受影响的行的锁定被释放，其他用户可以操纵那行；所有保存点被擦除。&lt;/p&gt;
&lt;p&gt;什么时候发起rollback命令：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户直接发出撤销命令&lt;/li&gt;
&lt;li&gt;某些时机程序代码段中出现异常和错误&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用save point命令在事务中建立标记点，并允许用户只回滚标记点之后的动作。&lt;/p&gt;
&lt;h3&gt;SQL语句的简单优化&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;避免使用&apos;*&apos;，在解析过程中，会将星号一次性转换成所有的列名，并通过查询数据字典完成，意味着耗费更多的事件&lt;/li&gt;
&lt;li&gt;尽量使用表的别名&lt;/li&gt;
&lt;li&gt;注意where子句中的连接顺序，将能够缩小范围的condition放到后面&lt;/li&gt;
&lt;li&gt;使用&apos;&amp;gt;=&apos;替代&apos;&amp;gt;&apos;&lt;/li&gt;
&lt;li&gt;用truncate代替delete，delete如果没有commit操作，回滚段中会存放删除操作恢复的消息，而truncate会让回滚段不再存放任何可被恢复的信息，因此很少的资源被调用，执行事件会很短&lt;/li&gt;
&lt;li&gt;尽量多的使用commit&lt;/li&gt;
&lt;li&gt;避免在索引列上使用函数&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Linux&lt;/h2&gt;
&lt;p&gt;安装linux：&lt;a href=&quot;https://www.bilibili.com/video/BV1HE411r7Ln&quot;&gt;2019最新,Linux详细安装教程&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;操作系统os是管理和控制计算机硬件资源的计算机程序，核心功能有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;syscall接口&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;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Linux是类Unix操作系统，可以管理计算机所有硬件资源，进行cpu调度，分配工作桌面，linux结构分为4个，从外到内分别为应用程序，shell程序（Bash），内核kernel和硬件。&lt;/p&gt;
&lt;p&gt;Linux特点如下：&lt;/p&gt;
&lt;ul&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;li&gt;移植性好&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;常用的远程接入工具：xshell，xftp&lt;/p&gt;
&lt;h3&gt;Linux用户管理&lt;/h3&gt;
&lt;p&gt;Linux系统是用id来区分用户的，分为User ID和Group ID，用户名或者组名用于方便人们的记忆。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户id保存路径：/etc/passwd&lt;/li&gt;
&lt;li&gt;组id保存路径：/etc/group&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;/etc/passwd文件中记录了单个用户的登录信息，每一行代表一个用户，用&apos;:&apos;分割成7个字段：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&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;1&lt;/td&gt;
&lt;td&gt;用户登录名&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;用户口令，加密的，/etc/shadow有真正的口令文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;指定用户的UID，用户登录进系统后，系统通过该值识别用户&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;组识别号GID，对应/etc/group文件中的一条记录&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;描述信息，用来保存用户的真实姓名和个人细节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;指定用户的主目录的绝对路径&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;用户登录系统时运行的shell程序名称，通常是一个shell程序的全路径名&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;群组管理方法如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;groupadd [-option] [group_name] # 新建群组
groupmod [-g n] [group_name]    # 修改群组
groupdel [group_name]           # 删除群组
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用户管理方法如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;useradd [-option] [user_name] # 新增用户
passwd [user_name] # 设置用户密码
usermod [-option] [user_name] # 修改用户属性
userdel [-option] [user_name] # 删除用户
who    # 查询当前登录系统的所有用户
id     # 查询当前用户的GID和UID
finger # 查询用户的属性信息
su [-] [user_name] # 切换用户
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;文件和目录管理&lt;/h3&gt;
&lt;p&gt;绝对路径是由根目录(/)开始写起的文件名或者目录名称，相对路径是相对于当前路径的文件名或者目录名称的写法。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;. 代表当前目录&lt;/li&gt;
&lt;li&gt;.. 代表上一级目录&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;pwd    # 显示当前工作目录
cd dir # 更改工作目录
ls [-option] [dir|file] # 查看文件或者目录
chown [-R] 文件主 文件    # 修改属主
chgrp [-R] 属有群组 文件  # 修改所属群组
chmod [-options] mode files 或者 chmod [ugoa] {+|-|=} [rwx] files # 修改权限

touch file # 新建文件
mkdir [-m 模式/权限] [-p] dir # 新增目录
cp [option] origin_file/dir target_file/dir  # 复制文件或目录
scp [option] origin_file/dir target_file/dir # 复制文件或目录，用于网络胡同的远程主机复制文件或目录，要求对其父目录具有写权限
mv [-fiu] origin_file/dir target_dir # 移动文件或目录
rmdir [-p] dir     # 删除目录
rm [-fir] file/dir # 删除文件或目录
find path [-option] [查找条件] # 查找文件或目录路径
cat file  # 直接查阅文件内容，不能翻页
more file # 翻页查看文件内容
less file # 翻页阅读
head file # 查看文件前几行内容，默认10行
tail file # 查看文件后几行内容，默认10行
grep [-cin] &apos;目标字符串&apos; file # 查找文件内容

command1 | command2 # 管道，将一个命令的输出连接到另一个命令的输入
command &amp;gt; file  # 输出重定向 (覆盖导入)
command &amp;gt;&amp;gt; file # 输出重定向 (从文件末尾导入) 
command &amp;lt; file  # 输入重定向
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;文件和目录的权限意义：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;read(r)：可读取此文件/目录的实际内容&lt;/li&gt;
&lt;li&gt;write(w)：可以编辑文件/目录（不包含删除该文件）&lt;/li&gt;
&lt;li&gt;execute(x)：该文件具有被系统执行的权限/具有进入该目录的权限&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;文件属性和权限说明（从左到右）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;前十位：文件类型(1)+owner权限(3)+group权限(3)+other权限(3)&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;/li&gt;
&lt;li&gt;最近修改日期&lt;/li&gt;
&lt;li&gt;文件名&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;vim编辑器&lt;/h3&gt;
&lt;p&gt;vim是类Unix系统内置文本编辑器，其他文本编辑器不一定存在。vim具有三种模式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一般模式：用esc进入&lt;/li&gt;
&lt;li&gt;编辑模式：从一般模式用i, o, a 或 R进入&lt;/li&gt;
&lt;li&gt;指令模式：从一般模式用:, / 或 ?进入&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&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;上下左右&lt;/td&gt;
&lt;td&gt;移动光标&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0或home键&lt;/td&gt;
&lt;td&gt;移动光标到行首字符处&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$或end键&lt;/td&gt;
&lt;td&gt;移动光标到行尾字符处&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gg&lt;/td&gt;
&lt;td&gt;移动光标到第一行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;G&lt;/td&gt;
&lt;td&gt;移动光标到最后一行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nG&lt;/td&gt;
&lt;td&gt;n为数字，移动光标到第n行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;: set nu&lt;/td&gt;
&lt;td&gt;显示行号&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/word&lt;/td&gt;
&lt;td&gt;向光标之下搜索名字为word的字符串&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;?word&lt;/td&gt;
&lt;td&gt;向光标之上搜索名字为word的字符串&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;n&lt;/td&gt;
&lt;td&gt;重复前一个搜寻动作&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;td&gt;重复前一个搜寻动作，但方向相反&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:n1,n2s/word1/word2/g&lt;/td&gt;
&lt;td&gt;在n1行和n2行之间搜索word1字符串，并且将该字符串替代为word2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:1,$s/word1/word2/g&lt;/td&gt;
&lt;td&gt;全文搜索word1字符串，并且将该字符串替代为word2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:1,$s/word1/word2/gc&lt;/td&gt;
&lt;td&gt;全文搜索word1字符串，并且将该字符串替代为word2，并在替换之前要求用户确认&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;delete键&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;backspace键&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nx&lt;/td&gt;
&lt;td&gt;delete n次&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dd&lt;/td&gt;
&lt;td&gt;删除光标所在一整行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ndd&lt;/td&gt;
&lt;td&gt;删除光标所在行向下n行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;yy&lt;/td&gt;
&lt;td&gt;复制光标所在行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nyy&lt;/td&gt;
&lt;td&gt;复制光标所在行向下n行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p&lt;/td&gt;
&lt;td&gt;将已经复制的数据，从光标下一行开始粘贴&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;u&lt;/td&gt;
&lt;td&gt;复原上一个动作&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.&lt;/td&gt;
&lt;td&gt;重复上一个动作&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;i&lt;/td&gt;
&lt;td&gt;进入insert模式，从目前光标所在处插入&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;a&lt;/td&gt;
&lt;td&gt;进入insert模式，从目前光标所在处的下一个字符插入&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;o&lt;/td&gt;
&lt;td&gt;进入insert模式，从目前光标所在处的下一行插入新的一行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r&lt;/td&gt;
&lt;td&gt;进入replace模式，取代光标所在字符一次&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;进入replace模式，一直取代直到esc为止&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;esc&lt;/td&gt;
&lt;td&gt;退出编辑模式到一般模式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:w&lt;/td&gt;
&lt;td&gt;将编辑的数据写入磁盘中&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:wq&lt;/td&gt;
&lt;td&gt;保存并退出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:q!&lt;/td&gt;
&lt;td&gt;不保存，强制退出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ZZ&lt;/td&gt;
&lt;td&gt;若文件没有被修改，则不存储退出。若文件被修改，则存储后退出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:w filename&lt;/td&gt;
&lt;td&gt;另存为&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:r filename&lt;/td&gt;
&lt;td&gt;将文件名为filename的文件内容读取到光标的后面&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Linux文件系统管理&lt;/h3&gt;
&lt;p&gt;文件系统是os用于明确存储和组织计算机数据的方法，即对一个存储设备上的数据和元数据进行组织的机制。它使得对数据的访问和查找变得容易。&lt;/p&gt;
&lt;p&gt;文件系统分类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;是否有日志？
&lt;ul&gt;
&lt;li&gt;传统型文件系统&lt;/li&gt;
&lt;li&gt;日志型文件系统&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;如何查找数据？
&lt;ul&gt;
&lt;li&gt;索引式文件系统：将文件属性数据和实际内容分别存放在不同你的区块，通过属性数据，可以快速找到实际数据所在。&lt;/li&gt;
&lt;li&gt;非索引式文件系统：只有block存在，读取数据时，需要一个block一个block读取，效率较低。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;目录树是如何读取的？从文件系统的顶层进行读取，获取inode号码并验证inode权限，然后根据该inode读取block内的文件名数据，再一层层往下读取到正确的档案内容。&lt;/p&gt;
&lt;p&gt;Linux磁盘是存在分区的。安装系统时首先会接触到分区。硬盘分区实质上是对硬盘的一种格式化，将硬盘逻辑的分成不同的槽/块。让数据能够分类存放在硬盘的不同区域中，以便更好地管理数据。硬盘分区按照功能的不同，分为以下几类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主分区3个&lt;/li&gt;
&lt;li&gt;扩展分区1个&lt;/li&gt;
&lt;li&gt;逻辑分区n个&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;fdisk -l    # 查看磁盘分区
fdisk 设备名 # 创建分区
mkfs [-t 类型] [-b block大小] 设备名称 # 创建文件系统
mount 设备名 挂载点   # 手动挂载文件系统
umount 设备名或挂载点 # 手动卸载文件系统
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;/etc/fstab配置了开机自动挂载的文件系统，系统挂载有以下限制：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;/目录必须挂载，并且一定要先于其他挂载点被挂载起来&lt;/li&gt;
&lt;li&gt;挂载点必须是已经存在的目录，可以任意指定&lt;/li&gt;
&lt;li&gt;所有文件系统只能在同一时间挂载一次&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;/etc/fstab每行有6个字段：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&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;1&lt;/td&gt;
&lt;td&gt;文件系统&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;挂载点&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;文件系统类型&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;文件系统参数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;是否采用dump备份&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;开机是否自检&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code&gt;df [-h|-i]    # 查看分区使用情况
du [-a|-s|-h] # 查询文件或目录的磁盘使用空间
lsof          # 查看打开的文件
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;网络管理&lt;/h3&gt;
&lt;p&gt;linux网络术语：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;设备：主机内的网卡&lt;/li&gt;
&lt;li&gt;链路：设备到网络的连接&lt;/li&gt;
&lt;li&gt;接口：为使用设备，驱动程序在设备上创建了接口&lt;/li&gt;
&lt;li&gt;子网掩码：将ip地址划分成网络地址和主机地址两部分的掩码&lt;/li&gt;
&lt;li&gt;广播地址：到达本网段上所有主机的地址&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ip的分类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a类网络：0.xxx.xxx.xxx - 127.xxx.xxx.xxx&lt;/li&gt;
&lt;li&gt;b类网络：128.xxx.xxx.xxx - 191.xxx.xxx.xxx&lt;/li&gt;
&lt;li&gt;c类网络：192.xxx.xxx.xxx - 223.xxx.xxx.xxx&lt;/li&gt;
&lt;li&gt;d类网络：224.xxx.xxx.xxx - 239.xxx.xxx.xxx&lt;/li&gt;
&lt;li&gt;e类网络：240.xxx.xxx.xxx - 255.xxx.xxx.xxx&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;ifconfig 接口 [-option] # 查看或设置网络接口的参数，如ip，掩码等
ifconfig 接口 up # 读取配置文件的方式启动网络接口
route # 查看路由表
route add [-net|-host] [netmask Nm] [gw Gw] [dev] # 新增到网段或者主机的路由
route add default gw # 暂时更改默认路由
route del [-net|-host] [netmask Nm] [gw Gw] [[dev] lf] # 删除到网段或者主机的路由

ping [-option] address # 检查网络是否通畅或者网络连接速度
traceroute [-option] &amp;lt;ipaddr or domain name&amp;gt; # 探测数据包从源到目的经过的路由器的ip
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Linux进程管理和服务管理&lt;/h3&gt;
&lt;p&gt;程序是文件中保存的一系列可执行命令。&lt;/p&gt;
&lt;p&gt;进程是加载到内存中的程序，有cpu运行。用户进程是用户通过终端加载的进程。守护进程是与终端无关的系统进程，可基于时间或事件启动。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ps aux  # 查看所有进程信息
top     # 连续观察进程动态，默认3秒更新一次
pstree  # 用ascii字符显示树状结构，表达程序间的相互关系
kill    # 结束进程
killall # 结束同一进程组内的所有进程
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;任务的概念与相关术语：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;任务：登录系统取得shell之后，在单一终端接口下启动的进程。在任务管理的行为当中，每个任务都是目前的shell的子进程，无法在一个shell下面取管理另外一个shell下面的任务。&lt;/li&gt;
&lt;li&gt;前台：在终端接口上，可以出现提示符让用户操作的环境。&lt;/li&gt;
&lt;li&gt;后台：不显示在终端接口的环境。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;任务管理可以多项任务并行，使用&lt;code&gt;&amp;amp;&lt;/code&gt;号执行。使用ctrl+z将正在运行的任务放入后台暂停。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;jobs       # 查看当前shell的后台的任务
fg %job ID # 将任务放入前台执行
bg %job ID # 将任务放入后台执行
crontab [-u user] [-e|-l|-r] # 周期计划任务
at # 安排一个任务在未来执行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;system daemon (systemd) 是linux下的一种init软件。作为init软件，systemd程序的任务有如下工作：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;初始化文件系统，设置环境变量&lt;/li&gt;
&lt;li&gt;挂载硬盘，/proc, /tmp, swap等&lt;/li&gt;
&lt;li&gt;根据设置的运行级别，启动相应的守护进程&lt;/li&gt;
&lt;li&gt;并在系统运行期间，监听整个文件系统&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;systemctl start|stop|status [service] # 通过systemctl管理服务
journalctl -u A.service # 查看A服务的日志
journalctl --system --since=today # 查看当天系统服务以及内核的日志
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Linux监控系统&lt;/h3&gt;
&lt;p&gt;作为系统管理员，我们需要监控哪些项目？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;系统是否正常启动？&lt;/li&gt;
&lt;li&gt;系统负载如何？&lt;/li&gt;
&lt;li&gt;系统是否有非法用户登录？&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;hwinfo --cpu  # 显示cpu信息
hwinfo --disk # 查看磁盘信息
iostat        # 输出cpu和磁盘io相关的统计信息
lspci         # 列出所有PCI设备
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;监控系统和进程的命令：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ps：用来显示当前进程状态，查看的是静态信息&lt;/li&gt;
&lt;li&gt;top：即时显示进程的动态&lt;/li&gt;
&lt;li&gt;uptime：查看系统已经开机的时间以及系统平均负载&lt;/li&gt;
&lt;li&gt;uname：查看系统版本相关信息，如内核号&lt;/li&gt;
&lt;li&gt;netstat：显示与ip，tcp，udp协议相关的统计数据，用于检验本机各端口的网络连接情况&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;who [option]            # 查看登录系统的用户
w [option] [user]       # 查看当前登录系统的用户以及用户当前的工作
finger [option] [user]  # 查看用户详细信息
last [option]           # 查看曾经登陆过系统的用户
lastlog [option] [user] # 查看用户最近一次登录的信息
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>编程工具演练</title><link>https://lllirunze.cn/posts/huawei-chuying-2/</link><guid isPermaLink="true">https://lllirunze.cn/posts/huawei-chuying-2/</guid><description>该文章讲述企业的代码开发流程。</description><pubDate>Tue, 08 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Git基础和实操&lt;/h2&gt;
&lt;h3&gt;版本控制工具简介&lt;/h3&gt;
&lt;p&gt;版本控制是一种记录一个或若干文件内容变化，以便将来查阅特定版本修订情况的系统，查看历史、恢复版本，保证多人协作不出问题。&lt;/p&gt;
&lt;p&gt;原始的版本控制是通过修改文件并保存文件副本来实现的，但命名随意，导致版本难辨新旧，无法辨别每一版的修改内容。&lt;/p&gt;
&lt;p&gt;有一些比较远古的版本控制工具：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;diff：用来比较两个文件或者目录之间的差异&lt;code&gt;diff -u left.c right.c&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;patch：diff的反向操作，我们把上述差异结果保存到文件中，假设差异结果为diff.txt
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;patch left.c diff.txt&lt;/code&gt;：通过diff.txt，把left.c变成right.c&lt;/li&gt;
&lt;li&gt;&lt;code&gt;patch -R right.c diff.txt&lt;/code&gt;：通过diff.txt，把right.c变成原来left.c的内容&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最早期的本地版本控制工具为RCS（Revision Control System）&lt;/p&gt;
&lt;p&gt;集中式版本控制工具：CVS（Concurrent Versions System）和SVN（Subversion），但是存在问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提交通道狭窄：不能同时修改、缺乏代码门禁&lt;/li&gt;
&lt;li&gt;数据安全性差：单点故障、黑客攻击&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;分布式版本控制系统：BitKeeper、Git&lt;/p&gt;
&lt;p&gt;Git是Linus（Linux之父）的第二个伟大作品。和其他版本控制系统相比，Git的差别在于&lt;strong&gt;对待数据的方法&lt;/strong&gt;，Git像是把数据看作是对小型文件系统的一组快照，每次提交更新时，它主要对当时的全部文件制作一个快照并保存这个快照的索引，变成一个&lt;strong&gt;快照流&lt;/strong&gt;。如果其中一个版本受到破坏，其他任何一个版本都不会受到影响。Git的好处如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据安全&lt;/li&gt;
&lt;li&gt;提交为本地操作，编码不会被冲突打断，可以移动办公&lt;/li&gt;
&lt;li&gt;数据和提交全部使用SHA1哈希，以保证完整性&lt;/li&gt;
&lt;li&gt;适合分布式开发，强调个体&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如何选择适合的版本控制工具：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SVN不适合的领域：
&lt;ul&gt;
&lt;li&gt;跨地域的协同开发&lt;/li&gt;
&lt;li&gt;对代码的高质量追求和代码门禁&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Git不适合的领域
&lt;ul&gt;
&lt;li&gt;不适合word等二进制文档的版本控制&lt;/li&gt;
&lt;li&gt;整体的读授权，不饿能将读授权精细到目录级别&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Git的安装和配置&lt;/h3&gt;
&lt;p&gt;在Linux下安装Git：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ubuntu或Debian
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sudo aptitude install git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo aptitude install git-doc git-svn git-email gitk&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;RHEL、Fedora、CentOS
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;yum install git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yum install git-svn git-email gitk&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;从源代码开始安装&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在Windows下安装Git：到git-scm网站下安装windows安装包，直接下载就行，安装过程中选择一些必要的组件（建议把git-lfs去掉），在选择是否修改环境变量时，选择“Use Git Bash Only”。安装完成后，右击屏幕并选中Git Bash就可以启动了。&lt;/p&gt;
&lt;p&gt;另外有一个基于msysGit的图形界面工具：TortoiseGit（小乌龟），直接到官网安装就可以。&lt;/p&gt;
&lt;p&gt;Git基本配置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置个人身份：
&lt;ul&gt;
&lt;li&gt;系统配置（适用于所有用户）：&lt;code&gt;git config --system xxx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;用户配置（适用于当前用户）：&lt;code&gt;git config --global xxx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;仓库配置（适用于当前项目）：&lt;code&gt;git config --local xxx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;配置个人身份：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git config --global user.name &quot;Zhangsan&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git config --global user.email zhangsan123@huawei.com&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;文本换行符配置：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git config --global core.autocrlf [true|input|false]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;文本编码配置
&lt;ul&gt;
&lt;li&gt;中文编码支持：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git config --global gui.encoding utf-8&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git config --global i18n.commitencoding utf-8&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git config --global i18n.logoutputencoding utf-8&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;显示路径中的中文
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git config --global core.quotepath false&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;与服务器的认证配置
&lt;ul&gt;
&lt;li&gt;http/https协议认证：
&lt;ul&gt;
&lt;li&gt;设置口令缓存：&lt;code&gt;git config --global credential.helper store&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;添加https证书信任：&lt;code&gt;git config http.sslverify false&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ssh协议认证
&lt;ul&gt;
&lt;li&gt;输入&lt;code&gt;ssh-keygen -t rsa -C zhangsan123@huawei.com&lt;/code&gt;生成公钥&lt;/li&gt;
&lt;li&gt;添加公钥到代码平台：进入代码平台的settings，找到SSH Keys，把公钥文件的内容复制到Public Key中保存&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Git基本命令&lt;/h3&gt;
&lt;p&gt;Git版本控制下的工程区域只有3种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;版本库：工作区中有一个隐藏目录.git，这个就是版本库，存放Git用来管理该工程的所有版本数据&lt;/li&gt;
&lt;li&gt;工作区：日常工作的代码文件或者文档所在的文件夹&lt;/li&gt;
&lt;li&gt;暂存区：一般放在工程根目录.git/index文件中，也叫索引index&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Git版本控制下的文件状态有3种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;已提交commit&lt;/li&gt;
&lt;li&gt;已修改modify&lt;/li&gt;
&lt;li&gt;已暂存stage&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Git常用命令如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 工程准备
git init              # 在本地目录下新建项目仓库
git [lfs] clone [URL] # 克隆远端工程到本地磁盘，如果所在的项目git服务器已经支持了git-lfs，对二进制文件进行了区别管理，那么克隆工程的时候务必使用git lfs clone，否则克隆操作无法下载到工程中的二进制文件导致工程内容不完整。

# 新增、删除、移动文件到暂存区
git add [file]                      # 把文件添加到暂存区，此时还没有提交
git rm [file]                       # 将指定文件彻底从当前分支的缓存区删除，因此它从当前分支的下一个提交快照中被删除
git mv [old_file] [folder|new_file] # 用于移动文件，也可以用于重命名文件

# 查看工作区
git diff [version1] [version2]              # 比较两个节点之间的差异
git diff [branch1]..[branch2]               # 比较两个分支之间的差异
git diff --cached                           # 比较当前索引和上次提交之间的差异
git diff [branch1]..[branch2] --name-status # 比较两个分支之间的差异，只看文件列表
git status                                  # 用于显示工作目录和暂存区的状态

# 提交更改的文件
git commit            # 将暂存区里的文件改动提交到本地的版本库
git commit -am &quot;xxx&quot;  # 一次性提交所有在暂存区改动的文件到版本库

# 查看日志
git log

# 推送远端仓库
git push [local_branch] [remote_branch] # 在使用git commit命令将自己的修改从暂存区提交到本地版本库后，可以使用push将本地版本库的分支推送到远程服务器上对应的分支

# 分支管理
git branch                                      # 查看本地工程的所有git分支名称
git branch -r                                   # 查看远端服务器上的分支
git branch -a                                   # 查看本地和远端的所有分支
git branch [branch]                             # 新建分支（但不会切换到新分支）
git branch -d [branch]                          # 删除分支
git branch -D [branch]                          # 强制删除分支
git branch -d -r [branch]                       # 删除远端分支
git checkout [branch]                           # 切换已有分支
git checkout -b [branch]                        # 新建分支（自动切换到新分支）
git checkout -f [branch]                        # 强制切换到已有分支
git pull origin [remote_branch]:[local_branch]  # 从远端服务器中获取某个分支的更新，再与本地指定的分支进行自动合并
git pull origin [remote_branch]                 # 如果远程指定的分支和本地指定的分支相同，直接pull更新
git fetch origin [remote_branch]:[local_branch] # 从远端服务器中获取某个分支的更新，但不会进行合并操作，确认fetch内容符合预期后，再决定是否手动合并节点
git fetch origin [remote_branch]                # 如果远程指定的分支和本地指定的分支相同，fetch更新

# 分支合并
git merge [branch]  # 从指定的分支合并到当前分支的操作
git rebase [branch] # 合并目标分支到当前分支

# 撤销操作
git reset [commit_id] # 将工作区内容回退到历史提交节点
git checkout .        # 用于回退本地所有修改但未提交的内容（有风险，谨慎使用）
git checkout -[file]  # 仅回退某个文件的未提交改动
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;IDEA常用快捷键&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&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;alt+insert&lt;/td&gt;
&lt;td&gt;新建&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;alt+上下箭头&lt;/td&gt;
&lt;td&gt;以函数为单位移动&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ctrl+g&lt;/td&gt;
&lt;td&gt;定位到行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ctrl+w&lt;/td&gt;
&lt;td&gt;可以选择单词继而语句继而行继而函数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ctrl+shift+w&lt;/td&gt;
&lt;td&gt;取消选择光标所在词&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;shift+shift&lt;/td&gt;
&lt;td&gt;查找任意文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ctrl+n&lt;/td&gt;
&lt;td&gt;查找java类&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ctrl+f&lt;/td&gt;
&lt;td&gt;查找&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ctrl+r&lt;/td&gt;
&lt;td&gt;替换&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;f4&lt;/td&gt;
&lt;td&gt;进入某一方法或者到变量定义处&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ctrl+f12&lt;/td&gt;
&lt;td&gt;查看方法和成员变量&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ctrl+alt+左右箭头&lt;/td&gt;
&lt;td&gt;回退/前进到上一次编辑处&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ctrl+d&lt;/td&gt;
&lt;td&gt;复制一行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ctrl+y&lt;/td&gt;
&lt;td&gt;删除一行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ctrl+ /&lt;/td&gt;
&lt;td&gt;选中一段进行注释/反注释&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;shift+f6&lt;/td&gt;
&lt;td&gt;重命名&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ctrl+alt+m&lt;/td&gt;
&lt;td&gt;抽取函数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ctrl+alt+v&lt;/td&gt;
&lt;td&gt;抽取变量&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ctrl+shift+f9/f10&lt;/td&gt;
&lt;td&gt;调试/运行测试用例&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ctrl+f8&lt;/td&gt;
&lt;td&gt;打断点/取消断点&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;shift+f9/f10&lt;/td&gt;
&lt;td&gt;调试/运行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;f7&lt;/td&gt;
&lt;td&gt;进入函数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;f8&lt;/td&gt;
&lt;td&gt;单步&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;f9&lt;/td&gt;
&lt;td&gt;到下一个断点或者结束&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;alt+f8&lt;/td&gt;
&lt;td&gt;查看表达式结果&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://youmeek.gitbooks.io/intellij-idea-tutorial/content/introduce.html&quot;&gt;IntelliJ-IDEA-Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1Ft411V7rf?vd_source=26ff51a077492205b3143e873e64057f&quot;&gt;IntelliJ IDEA神器使用技巧&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>雏鹰计划-学习启动会</title><link>https://lllirunze.cn/posts/huawei-chuying-1/</link><guid isPermaLink="true">https://lllirunze.cn/posts/huawei-chuying-1/</guid><description>从校园到职场。</description><pubDate>Mon, 24 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;为什么要有雏鹰计划&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;从校园到职场，编程有差异&lt;/li&gt;
&lt;li&gt;如何提升软件能力，职业化，缩短业务期&lt;/li&gt;
&lt;li&gt;编码基础，编码习惯clean code，写好代码的兴趣&lt;/li&gt;
&lt;li&gt;快速上手编码，转身进入工作状态，展现自我能力&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;培养方案&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;看懂业务代码（雏鹰计划），写好代码入职前2-3月&lt;/li&gt;
&lt;li&gt;软件范式培养5月&lt;/li&gt;
&lt;li&gt;软件高手、专家3年&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;雏鹰计划安排&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;线上宣讲3.12&lt;/li&gt;
&lt;li&gt;启动报名3.12&lt;/li&gt;
&lt;li&gt;学习，建立学习班集体（当周）&lt;/li&gt;
&lt;li&gt;定期组织，集中辅导（定期组织）&lt;/li&gt;
&lt;li&gt;结班典礼，总结，收获分享，学习之星揭晓，入职后培养体系介绍（5月底）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3+1模式开展学习活动&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;班长+导师（固定群内解答问题，每周半天）+班主任+新员工&lt;/li&gt;
&lt;li&gt;每周周报输出：每班每周课程安排+学习内容&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;课程介绍&lt;/h2&gt;
&lt;p&gt;这次是5.0，多了ai赋能、软件测试&lt;/p&gt;
&lt;p&gt;ilearning网站：&lt;strong&gt;软件雏鹰计划（java版）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;学习安排：建议学习周期1.5月，时间60h&lt;/p&gt;
&lt;h2&gt;nce数通业务介绍+技术布局&lt;/h2&gt;
&lt;p&gt;物理世界 &amp;lt;-----（园区网络、广域网络、数据中心网络+网络安全）-----&amp;gt;数字世界&lt;/p&gt;
&lt;p&gt;top5的kpi:网络可用性、网络安全、客户满意度、运营效率、运维自动化&lt;/p&gt;
&lt;p&gt;业务方向：围绕（智能业务变更、智能故障处置、智能体验保障、智能安全防护、智能生态集成）&lt;/p&gt;
&lt;p&gt;架构演进：从L3架构-基于规则  到  L4架构-基于知识&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一脑 - Net master智能大脑&lt;/li&gt;
&lt;li&gt;一图 - 高清数字地图&lt;/li&gt;
&lt;li&gt;一网 - 智能网元&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;技术方向：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一脑 智能决策： 固定规则 -&amp;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;CloudNative&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;雏鹰计划 前成员分享&lt;/h2&gt;
&lt;p&gt;雏鹰计划，本人是学python和c的，专业为医学人工智能，转语言有学习成本&lt;/p&gt;
&lt;p&gt;入职感受：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;拒绝焦虑，刚工作会迷茫，担心难以胜任 -&amp;gt; 正常现象。一开始不会安排特别难的任务，导师制，和大牛做好联络，不要吝啬提问，工作比上学忙碌。&lt;/li&gt;
&lt;li&gt;压力驱动，有精神物质激励&lt;/li&gt;
&lt;li&gt;日常活动&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>《经营未来》精选-3</title><link>https://lllirunze.cn/posts/reading-9787010068725-3/</link><guid isPermaLink="true">https://lllirunze.cn/posts/reading-9787010068725-3/</guid><description>遭遇困境时，最重要的事自己的意志。</description><pubDate>Wed, 05 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;血泪&lt;/h2&gt;
&lt;p&gt;新军部筹划的”调整重、化工业投资“政策使现代集团陷入了危机。无所不为的”国保委时代“来临了。&lt;/p&gt;
&lt;p&gt;一批从海外学成归来的经济学者，连同国内的一部分经济学家，纷纷参与到新军部经济政策的筹划活动中。他们把重、化学工业的重复投资视为韩国经济发展的障碍，主张积极改变这一经济模式。这一主张也暗合了那些试图改变国内经济格局的新军部领导人的想法。&lt;/p&gt;
&lt;p&gt;现如今，很少有人会把多家汽车生产公司共存的局面视为重复投资、国力浪费的现象。经济有其竞争规则，竞争应以公平为基础。竞争公平规则受到保障的程度是衡量先进国家与落后国家的标准之一。&lt;/p&gt;
&lt;p&gt;但在当时，一部分经济学家和官僚却坚持认为，只有把所有汽车制造厂融为一体同时发电设备厂也融为一体，才有利于国家经济的发展。具体说来，就是要把现代汽车、大宇汽车和亚细亚汽车合并为一家，再把电力设备领域的大宇玉浦造船厂、现代重工业，以及昌原的现代洋行（现斗山重工业）合并为一体。&lt;/p&gt;
&lt;p&gt;对于现代集团来说，汽车与电力设备好比手心、手背，哪一个都无法割舍。现代集团对汽车产业的期望与热情是很高的，何况当时，现代汽车刚刚起步走向世界。电力设备领域也是一样。现代集团已经具备了制造原子能发电设备的能力。如果放弃这一领域，就等于放弃巨大的火力发电站与核发电站设备市场。&lt;/p&gt;
&lt;p&gt;新军部的经济调整方案简直就像捕捉现代集团的一张阴沉的大网。但是，这一政策已经公开，留给我们的唯一选择就是作出取舍。&lt;/p&gt;
&lt;p&gt;经过智囊团的反复研究商议，郑会长最终决定选择汽车产业，因为这个新兴产业具有无限的发展空间，虽然电力设备产业也大有可为，但其生产本身就不具有稳定性，况且即使放弃了设备生产，今后我们至少还可以参与核电厂或火力发电厂的建设工程。现在想来，郑会长的判断也依然是明智的。&lt;/p&gt;
&lt;p&gt;内部意见统一之后，我便单枪匹马冲向了“国保委”。会谈的对象是陆军军校第17、18期出身的两位军官。他们直接让我作出选择。我说：&lt;/p&gt;
&lt;p&gt;“在作选择之前，我想先问一下，为什么要作这种选择？虽然现在看来，重、化工业似乎存在投资过剩，但在不远的将来一定会出现供不应求。如果把具有竞争力的企业都合并起来， 必然会违反市场经济的第一原则—一竞争， 进而导致经济衰退。 考虑到韩国经济的未来，我们认为这种投资调整本身就是有问题的。”&lt;/p&gt;
&lt;p&gt;“这个政策是经过充分论证、 研究过的，我看就没有必要在这里讨论了。 你们只需要从两个当中选择一个就行。”&lt;/p&gt;
&lt;p&gt;第一天的谈判毫无实质进展，但我能感觉到一点：“国保委”已经和现代集团的竞争对手达成了某种共识，我们成了被孤立的一方。他们一定希望我们放弃汽车、 选择电力设备。 不，他们或许已经内定了让现代集团选择电力设备，然后把我们往这个方向诱导。&lt;/p&gt;
&lt;p&gt;我第三次去“国保委”的时候， 会谈的军官终于摊牌了。&lt;/p&gt;
&lt;p&gt;“你们现代集团一直侧重于重工业发展，在这个领域也有过不少投资。 既然建筑是你们的主力行业， 选择电力设备也就顺理成章了。”&lt;/p&gt;
&lt;p&gt;“现代选择汽车产业。”我单刀直入。&lt;/p&gt;
&lt;p&gt;他们一下子慌了。&lt;/p&gt;
&lt;p&gt;接下来，他们开始强行要求我们选择电力设备。我毫不含糊地说：“现代集团从始至终不赞成合并，如果合并不可避免，那我们一定选择汽车产业。”&lt;/p&gt;
&lt;p&gt;那些军官自然不甘心，又罗列了一大堆现代集团应该选择电力设备的理由，但我丝毫没有动摇，谈判进入了僵持阶段。这时候，他们竟然把矛头指向了我个人：&lt;/p&gt;
&lt;p&gt;“你现在住在什么地方？”&lt;/p&gt;
&lt;p&gt;“江南。”&lt;/p&gt;
&lt;p&gt;“是公寓吗？ ”&lt;/p&gt;
&lt;p&gt;“不是， 独门独院， 不小。”&lt;/p&gt;
&lt;p&gt;“哼，你倒是住得宽敞。 而我，就住在山顶一间连自来水都没有保障的40平米的公寓里。 我们在为国家担忧的时候，你们却在一边享清福，还不肯跟政府合作，这像话吗？”&lt;/p&gt;
&lt;p&gt;我再也坐不住了。&lt;/p&gt;
&lt;p&gt;“两位花国家经费上军校的时候，我每天早上在梨泰院拉着平板车清理垃圾， 靠勤工俭学完成了学业。你们父母送你们进高中的时候，我不但要自己赚学费，还要拼命干活养活自己。大学毕业进入公司后，还要在国外工地没日没夜地工作。1974年我们国家外汇储备几近耗尽、国家经济面临崩溃的时候，是靠我们这些海外建设者辛辛苦苦挣的美金才扛了过去。两位从军校毕业后经历过战争吗？而我，每天都要在和战争一样残酷的海外市场上打拼，每天工作18个小时，每天晚上只能睡三四个小时。”&lt;/p&gt;
&lt;p&gt;这时， 一位军官拦住我的话。&lt;/p&gt;
&lt;p&gt;“我们也参加过战争。越南战争。”&lt;/p&gt;
&lt;p&gt;我忍住苦笑，又接着说：&lt;/p&gt;
&lt;p&gt;“谁说只有军人才是爱国者？我们这些企业人难道就不是爱国者吗？企业可以成为批评的对象，但无视企业作用的想法是绝对不可取的。你们住在山顶的公寓里，而我曾经在比那还要艰苦很多倍的地方生活过。作为一个大企业的社长，我住在一套大房子里有什么错吗？那套房子是公司为我方便接待外宾而盖的，如果这样也有错，难道一定要我降低自己的居住水平吗？难道这就是你们治国的目标吗？你们应该在最短的时间内，让你们这样的军人公务员也达到和我一样的富裕水准，这才是可取的目标。怎么可以要求一个靠诚实劳动富裕起来的人降低生活水平呢？”&lt;/p&gt;
&lt;p&gt;这一次的谈判在争论中结束了。我回到公司和郑会长商量，如果这样争论下去，我们必然会被推到选择的边缘，毕竟主动权不在我们手里。&lt;/p&gt;
&lt;p&gt;一天晚上，一个在政府部门工作的朋友托人捎来口信，说是想约我见一面。这位朋友当时正在辅助政府运作“改革”事宜，一看到我便露出担忧的神清。&lt;/p&gt;
&lt;p&gt;“李社长，现在是非常时期，很多问题不是固执己见就能解决 的。依我看，你还是同意吧。时间对你们不利啊。明天就去表态吧，这关系到现代集团的命运。”&lt;/p&gt;
&lt;p&gt;那天晚上，我一直在揣测他找我谈话的动机。是真心为我和现代集团担心，还是站在新军部立场上诱导我呢？我竟一时难以辨别。&lt;/p&gt;
&lt;p&gt;第二天，我向郑会长转达了那位朋友的话。
郑会长看上去很疲惫。“10·26”事件后，现代集团完全是靠他的坚韧意志与斗志才经受住了各种考验。肩扛千斤担的压力可想而知。&lt;/p&gt;
&lt;p&gt;“再努努力吧，如果实在不行，就同意吧。或许这就是大势所趋。”&lt;/p&gt;
&lt;p&gt;郑会长把公司的印章递给我。&lt;/p&gt;
&lt;p&gt;“会长，您这是做什么？”&lt;/p&gt;
&lt;p&gt;“你不要有思想负担。”&lt;/p&gt;
&lt;p&gt;“如果要盖章的话，还是请会长您亲自去吧。即使您不去，还有很多人能代表公司盖章啊。”&lt;/p&gt;
&lt;p&gt;“这件事一直是你在处理，你就善始善终吧。”&lt;/p&gt;
&lt;p&gt;我没再说什么， 收起印章，去了“国保委”。&lt;/p&gt;
&lt;p&gt;和往常一样，还是两条难以相交的平行线。 我继续坚持我的“不可合并论”。&lt;/p&gt;
&lt;p&gt;“如果把汽车企业捆成一个，竞争力就会降低，最终只能成为国家的负担。 印度就是一个前车之鉴：他们只有一家国营汽车企业，技术开发不行，经营管理也不行，造出来的汽车款式陈旧，性能也不好， 价格却贵得离谱。 因为产量少， 买一辆汽车要等上好几个月。 没有合理竞争的弊端，局外人是很难了解的。 我们国家现在看似重复投资， 但事实上是经济不景气、 产业化未能进入正轨所引起的。假以时日，就会体现出各个企业对出口所做的贡献。所以，还是请再考虑一下是否合并的问题。”&lt;/p&gt;
&lt;p&gt;“李社长，你以为你是谁啊？这个政策是以海归学者所做的调查报告为依据制定的。 你有什么资格在这里信口胡说？”&lt;/p&gt;
&lt;p&gt;我暗暗对自己说，务必再坚持一下。&lt;/p&gt;
&lt;p&gt;“我不知道那些人是以什么为根据主张合并的。那种废除合理竞争、 培养垄断企业才有助于资本主义社会发展的理论，在任何一本经济学教科书上都找不到。垄断企业一开始运转可能还不错，但时间一长，就会出现无数的问题；而在健康的竞争环境中成长 起来的企业，他们的前途将不可估量。 如果你们现在非要无理合并，能不能解决眼前问题还是未知数， 今后要想进入国际市场更是毫无希望。 到时候再后悔可就晚了。”&lt;/p&gt;
&lt;p&gt;“我们没时间听你在这儿讲课！要么同意合并，要么，请便。”&lt;/p&gt;
&lt;p&gt;此时已是深夜。 我意识到，再争论下去，也不会有什么转机。房间内的空气沉闷得让人透不过气来。&lt;/p&gt;
&lt;p&gt;“既然我们别无选择，那就请按政府的决定盖章吧。”&lt;/p&gt;
&lt;p&gt;我拿出郑会长的印章， 放在桌上。 我不能用我的手来盖这个章。&lt;/p&gt;
&lt;p&gt;一位下属军官走上前，拿起了印章，就在落章前的一瞬间，那位高级军官一脚踏开桌子， 站了起来。&lt;/p&gt;
&lt;p&gt;“不要盖！”&lt;/p&gt;
&lt;p&gt;他识破了我的意图。如果由他们盖章，由此产生的后果也将由他们承担。 他气急败坏地看着我， 又转头冲那位下属大发其火：&lt;/p&gt;
&lt;p&gt;“你怎么搞的！”&lt;/p&gt;
&lt;p&gt;那天半夜，我从“国保委” 出来，回到了公司。整个公司大楼，只有郑会长的办公室还亮着灯。&lt;/p&gt;
&lt;p&gt;郑会长盯着我的脸， 呆呆地看了好一会儿。&lt;/p&gt;
&lt;p&gt;“盖了吗？”&lt;/p&gt;
&lt;p&gt;“没盖， 章在这儿。”&lt;/p&gt;
&lt;p&gt;“啊？怎么回事？”&lt;/p&gt;
&lt;p&gt;“我明天再详细向您汇报吧。”&lt;/p&gt;
&lt;p&gt;郑会长又看着我的脸。&lt;/p&gt;
&lt;p&gt;“唉， 你的眼睛出血了。”&lt;/p&gt;
&lt;p&gt;“不会吧，我没觉得有什么异样啊。”&lt;/p&gt;
&lt;p&gt;“是出血了，去照照镜子吧。”&lt;/p&gt;
&lt;p&gt;在会长室入口的镜子前一照，果然我的眼睛里有红色的液体。沾在手帕上是乌紫色的。 这就是所谓的 “血泪＂ 吧！以前还以为只是文学性的修辞， 没想到从自己的眼睛里流下了血泪。&lt;/p&gt;
&lt;p&gt;我的正面对抗使 “国保委” 的汽车产业合并计划无法顺利进行， 进而促成了将问题移交工商部处理的契机， 合并问题也随之成为公开的争论。 在工商部主待的会议上， 郑周永会长更是强烈阐述了产业合并的弊端。 最终， 汽车产业没有走向合并之路。&lt;/p&gt;
&lt;p&gt;假如那时真的草草合并， 韩国现在的汽车产业水平或许就和印度无异了。 当时被合并的电力设备产业， 结果后患无穷。&lt;/p&gt;
&lt;h2&gt;奏响凯歌&lt;/h2&gt;
&lt;p&gt;1987年12月，国家电力公司开始为灵光核电站三、四期工程建设实施招标。当时，国内拥有核电站建设经验的只有现代建设和东亚建设两家公司。&lt;/p&gt;
&lt;p&gt;核电站分为核反应堆和电力生产装置两个部分。在之前的古里核电站一、二期与月城核电站一、二期工程中，现代建设负责建造了第一部分核反应堆工程，第二部分由东亚建设公司负责建造。此后的灵光核电站一、二期工程则是由现代建设全权负责的。所以，现代建设是国内唯一一家具备建设完整的核电站经验与能力的企业。政府和现代建设就灵光核电站三、四期工程签订授意合同是最为理想的。&lt;/p&gt;
&lt;p&gt;按照当时的情况，签订授意合同只是表示一种意向。《预算会计法》规定，大型工程不能和特定的公司签订承包合同，以防止给予特殊优惠待遇。事实上，政府不和现代建设签订核电站建设合同还有政治上的问题。由于此前政府无理介入现代集团的极东石油经营权问题，郑周永社长和第五共和国的权力层之间出现了裂痕。在这种情况下，政府自然不会让“现代”轻松过关。&lt;/p&gt;
&lt;p&gt;就在这时，发生了一件让韩国当局进退两难的事情：美国三里岛核电站发生核物质泄漏，引起全世界对核电站安全问题的关注。没有经验的公司不能参与核电站工程建设成为一种国际共识。&lt;/p&gt;
&lt;p&gt;韩国政府不愿把项目交给“现代”，但又不能不顾及舆论的巨大压力。于是，国家电力公司决定重新招标，并提出了新的竞标资格要求。&lt;/p&gt;
&lt;p&gt;第一次公告的标书审查结果是，只有“现代”符合要求。国家电力公司发出第二次公告，结果还是“现代”胜出。根据法律，通过两次审定的公司，第三次就可以与之签订承包合同。&lt;/p&gt;
&lt;p&gt;看到工程授意合同基本确定，我便去了新加坡处理公司其他事务。谁知几天后，我突然接到郑会长打来的国际长途电话。&lt;/p&gt;
&lt;p&gt;“李社长，核电站的授意合同无效了。”&lt;/p&gt;
&lt;p&gt;“怎么回事？”&lt;/p&gt;
&lt;p&gt;“是副总理在刚刚召开的记者招待会上公布的。你赶紧回来处理一下……”&lt;/p&gt;
&lt;p&gt;当时，在大部分政府主持的工程中，建设公司向政府提供政治资金是一种管理。但这次的核电站工程受到国内外普遍关注，资金猫腻难有藏身之地，政府权力层因此感到不快。&lt;/p&gt;
&lt;p&gt;在我离开的那几天，副总理、安全企划部长等政府高层竟然找出授意合同中的漏洞，随即召开记者招待会，宣布取消与“现代”的合同，并再次进行招标。&lt;/p&gt;
&lt;p&gt;一回国，我便直奔郑寅用副总理办公室。&lt;/p&gt;
&lt;p&gt;“政府怎么能不和合同当事人打招呼，就单方面取消合同呢？现代建设是经过一次、两次、三次竞标，堂堂正正地拿下了这个项目。政府单方面撕毁了合同，是要负法律责任的。我们恳请政府取消这一决定，否则我们将不得不对政府提起诉讼。”&lt;/p&gt;
&lt;p&gt;从副总理办公室出来后，我又去找国家电力公司的朴正基社长。&lt;/p&gt;
&lt;p&gt;“如果您按照副总理的要求取消合同，那就等于承认之前和我们签订合同是错误的。您只有强烈主张和我们签订的合同是合法的，并且按原计划进行，才能证明您之前的做法是正确的。否则，单方面撕毁合同的所有责任都将由您来承担。”&lt;/p&gt;
&lt;p&gt;朴社长处境尴尬。作为国家电力公司的社长，改变已经上报总统的决定几乎是不可能的。&lt;/p&gt;
&lt;p&gt;下一步，我又去找动力资源部的崔昌洛部长。&lt;/p&gt;
&lt;p&gt;“法律规定，不能以政治方式取消合法的工程合同。这次单方面撕毁与我们的合同，政府究竟是什么意思？”&lt;/p&gt;
&lt;p&gt;崔部长似乎欲言又止。&lt;/p&gt;
&lt;p&gt;后来，国家电力公司的朴社长向我转达了崔部长的意思：这个问题不归副总理管辖，更不是副总理应该出面处理的事情；虽然知道其中又不妥之处，但对于上面已经决定了的事情，他也不方便对外发表意见。&lt;/p&gt;
&lt;p&gt;明白了崔部长的意思之后，我再一次走进了他的办公室。&lt;/p&gt;
&lt;p&gt;“部长您只要肯定我的看法就行。等到合适的时机，请您再表明自己的态度吧。”&lt;/p&gt;
&lt;p&gt;我没有必要让崔部长为难。虽然现代建设的反抗不容忽视，但政府也不会轻易改变决定。&lt;/p&gt;
&lt;p&gt;在听了我的陈述之后，国家电力公司的朴社长主张必须深证考虑核电站建设的安全问题，并决定按照合同与现代建设合作。这自然引起了政府权力层的强烈不满，很快，他们便撤掉了朴社长的职务。接任的韩凤洙社长对此问题毫无作为。无奈之下，现代建设只得请律师做好诉讼准备，并通告了政府。诉讼对象是国家电力公司社长和动力资源部部长。&lt;/p&gt;
&lt;p&gt;终于，崔部长来找我了：&lt;/p&gt;
&lt;p&gt;“请你们承认政府权威。即便道理在你们一边，政府也不可能取消已经作出的决定。希望你们和东亚建设一起，再进行一次竞标。”&lt;/p&gt;
&lt;p&gt;虽然这个提议依然违背原则，但我们决定接受。我提出一个条件：&lt;/p&gt;
&lt;p&gt;“核电厂工程事关重大，招标不能以标书总额为准，必须以标书中的明细数据内容为准。”&lt;/p&gt;
&lt;p&gt;明细数据内容涉及很多具体的技术指标。没有核电站建设经验的企业是不可能提供这些数据的。政府接受了我的条件。&lt;/p&gt;
&lt;p&gt;竞标结果，灵光核电站三、四期工程项目，依然花落“现代”！&lt;/p&gt;
&lt;p&gt;这是一项工程两次被同一家公司赢得的珍贵记录。事实上，也是第一次在政府主持的重大项目中，企业没有向政府提供政治资金。&lt;/p&gt;
&lt;p&gt;在吸取了LNG储藏基地项目的失败教训之后，在两次起落、奋力抗争之后，我们终于奏响了嘹亮的凯歌。&lt;/p&gt;
</content:encoded></item><item><title>《经营未来》精选-2</title><link>https://lllirunze.cn/posts/reading-9787010068725-2/</link><guid isPermaLink="true">https://lllirunze.cn/posts/reading-9787010068725-2/</guid><description>对于年轻人来说，工作就是最好的福利。</description><pubDate>Mon, 24 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;初生牛犊不怕虎&lt;/h2&gt;
&lt;p&gt;10月初，我第一次担任了镇海第四肥料建设工程的工地出纳。工长是一位资历颇高的技术员，和那个年代的大多数技术员一样，他没有在大学接受过系统教育，但从日本侵略时期就开始积累了丰富经验。作为不折不扣的“工地型”任务，他特别不喜欢“乳臭未干的书呆子”，当然我也被包括在内。&lt;/p&gt;
&lt;p&gt;给职员预支款是我作为出纳的主要工作之一。职员们通常都在下午5点之后找我预支。他们忙了一天，下班后才想到我这儿来，我自然是尽我所能给予方便。但这种做法却引起了工长的不满。&lt;/p&gt;
&lt;p&gt;“喂，5点以后还给什么预支啊？你见过哪家银行在5点以后给钱的吗？”&lt;/p&gt;
&lt;p&gt;真是不可理喻，银行是银行，工地是工地。难道让忙得焦头烂额的技术员们在工作时间放下手里的活，到我这里来排队吗？心里虽这么想，但我不能反对，因为工长的话符合原则。&lt;/p&gt;
&lt;p&gt;几天后的一个下午，工长找我来预支，但当时已经过了5点。&lt;/p&gt;
&lt;p&gt;“不行！”&lt;/p&gt;
&lt;p&gt;“什么？”&lt;/p&gt;
&lt;p&gt;工长瞪大了眼睛。这个毛头小子竟敢公然违抗工长的命令。&lt;/p&gt;
&lt;p&gt;“没时间跟你开玩笑，快给我，有急用！”&lt;/p&gt;
&lt;p&gt;“5点以后是禁止现金支出的。&quot;&lt;/p&gt;
&lt;p&gt;”我知道，但我是工长！“&lt;/p&gt;
&lt;p&gt;”正因为您是工长，如果您把自己定的规矩打破了，我想以后就不会有人再遵守了。所以，现在绝对不能预支！“&lt;/p&gt;
&lt;p&gt;”你是不是疯了？太不像话了！小子，这是办公事用的，是非常紧要的事情，明白吗？“&lt;/p&gt;
&lt;p&gt;”遵守公司纪律也是很紧要的事情！“&lt;/p&gt;
&lt;p&gt;”是吗？呼……天啊！“&lt;/p&gt;
&lt;p&gt;工长无可奈何地走了。在那之后，我时刻准备着接受工长地报复，但情况却出乎我的意料。后来每次我去银行办事，工长都会用他的车送我去，然后再去办他自己的事。他似乎反而更看重我了。&lt;/p&gt;
&lt;p&gt;有一天，他突然对我说了这么一句话：&lt;/p&gt;
&lt;p&gt;”李先生，你将来肯定会成为公司的大人物。“&lt;/p&gt;
&lt;p&gt;12月初，公司突然通知我，要派我去泰国工地。镇海工地对我来说是一所大学校，当时国内的建筑企业对使用整套设备的工程毫无经验，不仅是我，现场所有人员都在犯错、改正的反复施行中摸索着前进的道路。这时候派我去海外，无疑是对我这段时间工作的肯定。&lt;/p&gt;
&lt;p&gt;我将参与的芭迪雅-那拉迪瓦高速公路建设工程是韩国建筑史上的第一项海外工程。这是连接位于泰国南部、马来西亚边境的两个城市的第二条公路，全场98公里，于1965年9月30日开始国际竞标。现代建设与西德、日本、法国、意大利、荷兰等16个国家的29家公司展开竞争，最终以最低成交价拿下了这项工程。当时的成交价为522万美元，比现代建设一年的销售额还要多。&lt;/p&gt;
&lt;p&gt;这项工程意义重大。当时连大企业都不敢做的事，竟然由”现代“这个名不见经传的中小企业做起来了。正是因为有这样的开拓精神，”现代“才会发展到如今的规模。&lt;/p&gt;
&lt;p&gt;泰国工地的指挥部比首尔的公司总部还要庞大。我是现场最基层的出纳人员，上面有经理科长，再上面有管理部长。整个工程于1966年1月7日正式动工，但进展得很不顺利。当时在韩国，连”高速公路“这个词都比较陌生，建设装备、技术人员都是捉襟见肘。美国人看到我们从国内运来的旧设备后直摇头：”你们要是能在5年内完成这个项目，我们把姓都改了。“&lt;/p&gt;
&lt;p&gt;为了节省劳务费，我们用了很多泰国工人，但由于语言不通和管理不善，摩擦、冲突时有发生。第一年投入了工程预算的70%，但工程进度只完成了30%。颜面尽失还是次要问题，最重要的是公司面临存亡危机。&lt;/p&gt;
&lt;p&gt;工地内部矛盾达到白热化的那天晚上，我正在办公室里整理账簿，当时屋里还有公司雇用的两个泰国经理人员。&lt;/p&gt;
&lt;p&gt;突然，外面一阵嘈杂，我身旁的泰国经理往窗外一看，急忙对我说：&lt;/p&gt;
&lt;p&gt;”李先生，快跑吧！“&lt;/p&gt;
&lt;p&gt;原来是从韩国来的工人在闹事。他们挥舞着军用短刀，把现场搞得一片狼藉。干部们闻风而逃，现场只剩下我一个不是暴徒的韩国人，泰国人留下的居然更多。&lt;/p&gt;
&lt;p&gt;那些暴徒好像把我的办公室当成了最终目标，一阵大吼大叫地冲了过来。两位泰国经理只好躲开，办公室里只剩下我一个人。&lt;/p&gt;
&lt;p&gt;”嘭“地一声，办公室的门被撞开了，一股浓烈的酒味扑面而来。我一看，大约有15个人，手持刀棍，喘着粗气。突然，其中一个人猛地把短刀扎在我的办公桌上。&lt;/p&gt;
&lt;p&gt;”趁老子心情好，乖乖地把保险柜钥匙交出来。“&lt;/p&gt;
&lt;p&gt;”不交！“&lt;/p&gt;
&lt;p&gt;”你想死啊？“&lt;/p&gt;
&lt;p&gt;看那架势，好像要用刀刺我的脸，我后退几步，把身体紧靠在墙上。&lt;/p&gt;
&lt;p&gt;”不肯交钥匙？看你能撑多久！“&lt;/p&gt;
&lt;p&gt;短刀刺向我脖子左边，我下意识地把头往右边一转，眼前一片漆黑。接着，刀又刺向右边，我赶紧把头转向左边。&lt;/p&gt;
&lt;p&gt;一脚伸进了鬼门关，我突然想，把钥匙给他们算了。其实保险柜里只有一点零钱，而且在这种情况下即使我交出钥匙也没有人会说什么。但最终，我还是没有把钥匙交给他们。这不是出于什么使命感，只是因为我不愿屈服的本能！&lt;/p&gt;
&lt;p&gt;”不交钥匙也行，帮我们把保险柜打开就行！“&lt;/p&gt;
&lt;p&gt;他们看短刀的威胁不起作用，就指着保险柜让我打开。我朝保险柜挪了两三步，然后猛地把保险柜抱在胸口。&lt;/p&gt;
&lt;p&gt;”兄弟们，揍他！“&lt;/p&gt;
&lt;p&gt;一阵拳打脚踢……&lt;/p&gt;
&lt;p&gt;我感觉浑身冒火似地疼痛，但还是死死地抱住保险柜。&lt;/p&gt;
&lt;p&gt;这时，耳畔传来警车地鸣叫声，暴徒们见势不妙，一哄而散。和警察一起冲进来的职员们看到抱着保险柜几近昏迷的我，立刻明白了事态，良久沉默不语。&lt;/p&gt;
&lt;p&gt;这件事很快传到了首尔总部。&lt;/p&gt;
&lt;p&gt;”李明博不惜生命保住了公司保险柜。“&lt;/p&gt;
&lt;p&gt;……&lt;/p&gt;
&lt;p&gt;”泰国工地保险柜事件“成了我在”现代”扎根的契机。&lt;/p&gt;
&lt;h2&gt;推土机&lt;/h2&gt;
&lt;p&gt;现代建设在越南承接的新工程弥补了在泰国的亏损，从而打下了重振旗鼓的基石；在国内，也通过京釜高速公路的建设打了一场漂亮的胜仗。&lt;/p&gt;
&lt;p&gt;京釜高速公路工程被誉为“檀君以来最伟大的历史。”这一战略计划实际上是朴正熙总统“打通国家大动脉，经济才能搞活”的信念，和郑周永社长“我们当然可以”的豪言壮语一拍即合的产物。&lt;/p&gt;
&lt;p&gt;1968年3月，当我完成泰国高速公路工程回到国内后，郑社长决定把我派往西冰库，担任现代建设重型机械事务所的管理科长。&lt;/p&gt;
&lt;p&gt;我一下子如坠冰窟。重机所很少有正规大学出身的职员加入，只有临时工和刚从工地回来、尚无去处的人才会被安排到那里。按说，我在国外工作了3年，虽然进行的是亏损工程的收尾工作，但毕竟还算圆满地完成了任务，回国后理应进入总部管理部或经理部，哪曾想到会被派到了那么一个不得人心的地方。&lt;/p&gt;
&lt;p&gt;我在人们同情、担心甚至嘲讽的目光中，默默地来到了西冰库工厂。在自称“老油条”的驾驶员和维修人员当中，有好多都拥有二十多年工作经验，是早在现代建设公司创立之前，就和郑周永社长一同打造汽车服务工厂的技术老手。他们都在人称“王常务”的重机所所长金永柱常务手下工作，因此人称“王党派”。&lt;/p&gt;
&lt;p&gt;我这个新任管理科长的”第一把火”就是要改变这些”王党派“的旧观念和工作态度。在重机领域工作的人都习惯于使用日本式的配件术语，如果碰到大学刚毕业、熟记英语术语的年轻技术员，连沟通都成了问题。&lt;/p&gt;
&lt;p&gt;我把新旧两派召集到一起。&lt;/p&gt;
&lt;p&gt;”我们现在使用的不是美8军留下的古董，而是最新的进口设备，以后我们也会越来越多地向美国公司订购配件。如果把differential gear（差动齿轮）说成‘代5（Dae Woo.gear的日式外来韩语）’，谁能听得懂呢？只记住配件名称还不够，每个配件上标注的固定编号也要一并记住，因为只凭名称是没法区分规格和生产厂家的。所以，今后申请配件的时候，务必先看好手册中的编号。如果像以前那样光说‘要代5’，我是不会批的。“&lt;/p&gt;
&lt;p&gt;为了掌握配件的名称和编号，”王党派”开始经常请教那些年轻技工，工厂的氛围有了很大改变。&lt;/p&gt;
&lt;p&gt;当时，重机事务所的一个重要任务就是支持京釜高速公路建设，因此需要更严格的纪律和紧迫感。我把上班时间从7点提前到了6点。无论男女老少，所有人一律6点在运动场集合，做10分钟体操，再围着西冰库工厂跑20分钟，以良好的精神状态投入工作。休息时间禁止打牌、下棋，即便是星期六下午，我也不允许在工作场所存在松懈的工作态度。&lt;/p&gt;
&lt;p&gt;老员工们虽然嘴上嘟囔着“没赶上好时候啊，遇到这么个年轻家伙，真是活受罪”，但行动上还是遵守规定的；可女员工们不干了。&lt;/p&gt;
&lt;p&gt;“6点上班对我们女员工来说太难了。男的只要洗漱一下就可以出门，可我们光是化妆就得要30分钟。请让我们比男的晚上班30分钟吧。”&lt;/p&gt;
&lt;p&gt;我不能动摇。&lt;/p&gt;
&lt;p&gt;“男员工晚上九十点钟才下班，而你们一般七八点就可以回家。你们可以利用晚上的富余时间，化好妆再睡觉嘛。早上起来刷一下牙就可以出门了。”&lt;/p&gt;
&lt;p&gt;女员工们气坏了，但也无可奈何。按现在来说，这简直不成体统，但我们那一代正是靠着这样的努力才战胜了贫穷。&lt;/p&gt;
&lt;p&gt;京釜高速公路工程是韩国建筑业的转折点。在那之后，使用机械设备进行建设施工受到认可；于是，重机所的作用也变得越来越重要。如果不能及时提供设备，工程进度就会受到影响。&lt;/p&gt;
&lt;p&gt;郑社长每天都会打好几次电话来催促设备维修工作。他对设备的名称、性能、配件了如指掌，而我作为管理科长却完全摸不着头脑，也就免不了要被电话那头的郑社长一顿痛斥。&lt;/p&gt;
&lt;p&gt;不仅仅在电话里，有时候郑社长会“从天而降”，冲我们大发脾气：“工地上因为没有设备而停工，你们重机所到底在干吗呢！”&lt;/p&gt;
&lt;p&gt;有一天，我又被训斥了一顿。那天晚上，我把一台因无法及时修理而未能送到工地的D8型推土机，以及一台构造相似的HD16型推土机全部拆开。大家都骂我疯了，因为那是需要紧急修理后马上送往工地的。我打开说明书，熟记每一个配件的名称和功能，然后再重新组装起来。&lt;/p&gt;
&lt;p&gt;我为什么要拆推土机？因为我知道，掌握了设备，才能掌握人。从性格来说，我也绝对不能忍受让难题来束缚和压制我。&lt;/p&gt;
&lt;p&gt;我不仅用这股“疯劲”征服了推土机，后来还用推土机推掉了一个“青瓦台的指示”。&lt;/p&gt;
&lt;p&gt;当时，我们的西冰库工厂旁边有家生产建材的企业共荣社。因为粉尘问题，两家公司发生了纠纷。机械和粉尘是水火不容的。我们的重型设备随时都要和粉尘做斗争。经过交涉，他们答应安装粉尘设备，但却迟迟不见行动。&lt;/p&gt;
&lt;p&gt;一天，我又给他们的负责人打电话，要求他们遵守约定。但一直到那天晚上他们也没有采取相应措施，反而加班加点“制造”粉尘。我打电话提出强烈抗议。对方理直气壮地说：&lt;/p&gt;
&lt;p&gt;“青瓦台让我们供应混凝土搅拌车，没办法，只能24小时开工。”&lt;/p&gt;
&lt;p&gt;“那是你们和青瓦台的事，你们必须遵守和我们的约定！”&lt;/p&gt;
&lt;p&gt;“和你们的约定算什么？青瓦台的指示谁敢违抗？”&lt;/p&gt;
&lt;p&gt;我大为光火，发出最后通牒：&lt;/p&gt;
&lt;p&gt;“我们等到今晚12点。如果你们再不采取措施，明天早上你们就别想干活了。”&lt;/p&gt;
&lt;p&gt;到第二天早上，他们还是一点动静都没有。我跳上推土机，一路开过去，在他们卡车出入的道路上挖了一道深沟。对方急红了眼，让我们把道路恢复原样，我说不能服从。这时，青瓦台直接打来了电话，我依然没有让步。&lt;/p&gt;
&lt;p&gt;“道路能不能恢复取决于他们。因为他们不遵守和我们的约定，才发生了这种事，所以请青瓦台不要干预。我不知道他们的交货情况有多么紧迫，但如果我们的设备不能按时维修，高速公路工程将会受到严重影响。”&lt;/p&gt;
&lt;p&gt;到了晚上，那家企业终于低头让步。&lt;/p&gt;
&lt;p&gt;把道路恢复原样后，我接到了现代总部打来的谴责电话。&lt;/p&gt;
&lt;p&gt;“为什么没有请示总部，惹出那样的祸来？”&lt;/p&gt;
&lt;p&gt;“既然是在现场出现的问题，当然该由我负责处理。如果请示总部，总部怎么跟青瓦台对抗啊？”&lt;/p&gt;
&lt;p&gt;这回，总部也无话可说了。据说后来，青瓦台的重要人物给现代总部的高层打电话问：&lt;/p&gt;
&lt;p&gt;“你们那位管理科长到底是什么人？怎么做出那种事来？”&lt;/p&gt;
&lt;p&gt;我们这边只好一阵敷衍：&lt;/p&gt;
&lt;p&gt;”是个只知道原则的年轻科长，还不懂人情世故，请多多谅解吧。“&lt;/p&gt;
&lt;h2&gt;家庭与财产&lt;/h2&gt;
&lt;p&gt;在我还是现代公司的一名小职员时，贫穷依然伴随着我。能拥有一间小屋已经是奢侈的想法，更不用说结婚、成家了。随着职位不断上升，在我28岁成为“前途无量”的理事之后，有人开始为我做媒了，介绍的对象大多是有钱人家的女儿，或者政治世家的千金，也有演艺界的漂亮女明星。&lt;/p&gt;
&lt;p&gt;但事实上，我内心里并没有人们想象的那种优越感，富贵名媛对我来说反而是一种负担。&lt;/p&gt;
&lt;p&gt;有一天，在浦项念高中时的一位英语老师把他朋友的妹妹介绍给了我。她不是有钱人家的女儿，父母都是清廉的公职人员，这一层就已经让我对她产生了好感。1970年我们见面的时候，她刚从梨花女子大学毕业。据说她在学校时，还曾被选为校花。但在我眼里，她并不是那种特别漂亮、出挑的女孩，而是一个心底善良的姑娘。由于工作繁忙，我几乎没有和她好好约会过。即使偶尔约了她，也总是“迟到早退”。有几次忙得脱不开身，只好打电话到约定的咖啡厅，让她换到饭店，然后还是不能按时去，只能让她自己吃饭。有时候让她等得太晚，只好让公司的司机替我把她送回家。&lt;/p&gt;
&lt;p&gt;在举行订婚仪式的那天，我也是因为有紧急事务要处理，仪式一结束便扔下她，直奔公司。据说那天，妻子的很多朋友还在那里议论：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/images/posts/reading/Snipaste_2025-02-27_23-57-28.png&quot; alt=&quot;pic2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;“怎么嫁了个这么丑的男人？”&lt;/p&gt;
&lt;p&gt;曾经的校花嫁了我这么个“难看的复合体”，也难怪他们会这么说。&lt;/p&gt;
&lt;p&gt;结婚后，我们用朋友们送的结婚礼金，在麻浦租了一间十几坪的月租房。每隔半年，房东就要求提高租金，所以3年内我们搬了8次家。第二次搬家的时候还带着全部的行李；但从第三次搬家开始，就只带走些生活必需品；到第七次，只拿了碗筷就离开了。有时候我甚至忘记已经搬了家，下班后又回到原来的住处。&lt;/p&gt;
&lt;p&gt;妻子从我还是穷小子的时候起，就和我一同为生活奋斗，是与我患难与共的“糟糠之妻”；但有那么一段时间，她竟然被误认为是我的“情人”。&lt;/p&gt;
&lt;p&gt;事情是这样的：当时我们住在由公司提供的狎鸥亭洞“现代公寓”。我经常一大早就出门，夜里很晚才回到家，邻居们很少看到我，只见过我妻子。因为我当时已经担任现代建设的社长，人们猜测我至少有50多岁，我的夫人当然就该是40多岁的中年妇女。但事实上，我妻子当时才29岁。&lt;/p&gt;
&lt;p&gt;当她带着小女儿去市场买东西时，有人就说：“瞧，那是现代公司的社长夫人”。“不会吧？社长夫人怎么可能这么年轻！”一来二去，这些话就被传成了“现代公司的社长和年轻情人生活在一起”，真是让人哭笑不得。&lt;/p&gt;
&lt;p&gt;我的家庭完全是妻子一个人在操持。三个女儿和一个儿子出生的时候，我一次都没有守在妻子身边。因为工作忙，和家人在一起的时间实在太少了。我一直觉得自己不是一个好爸爸，很少为孩子们做些什么，到国外出差也没有给他们买过什么礼物，顶多带回来飞机上赠送的洗漱用品什么的。孩子们小的时候，都以为那是爸爸特意从国外带回来的好东西，长大后才发现全然不是那么回事。&lt;/p&gt;
&lt;p&gt;但即便如此，我的孩子们依然会说：“爸爸是最关心我们的人。”这不是孩子们说的“假话”，而是我为人之父的“秘诀”所起的作用吧。我的秘诀就是通过妻子了解孩子们的作息安排。比如，孩子们考试、演出或野游的日期、内容都要向妻子问清楚，还有做些笔记。&lt;/p&gt;
&lt;p&gt;“我是爸爸，我现在在新加坡。这里正下着雨呢，家里呢？”&lt;/p&gt;
&lt;p&gt;就这样，先聊聊天气，然后再问考试之类的情况。&lt;/p&gt;
&lt;p&gt;“今天考试顺利吗？是不是考语文、数学、物理这三门？”&lt;/p&gt;
&lt;p&gt;“啊？！爸爸你怎么知道的？”&lt;/p&gt;
&lt;p&gt;我边笑边看笔记：&lt;/p&gt;
&lt;p&gt;“明天要考英语和历史吧？”&lt;/p&gt;
&lt;p&gt;这样，孩子们就会想，“爸爸多关心我啊！”&lt;/p&gt;
&lt;p&gt;就像我记住孩子们的日常生活一样，我也完全向孩子们公开我的生活。如果孩子们知道父母在什么地方、做些什么，这样的家庭往往不需要过多地为孩子操心。父母的言传身教是对孩子最好的帮助。&lt;/p&gt;
&lt;p&gt;在我担任现代公司社长的时候，曾经参加过一个谈话节目。当时社会上对公开公职者的财产十分关注。我在节目中强调说，社会舆论支持的不应是“清贫论”，而应是“清富论”。这番谈话引起了不小的波澜。&lt;/p&gt;
&lt;p&gt;财产的多少并不是问题的关键。如果积累的方式不正当，即使很少的一点财产也是不正当的财产；反之，如果方式政党，凭智慧与勤劳致富，财产很多也是合情合理。当然，通过不正当方法致富的一些企业和个人是需要反对和查办的。&lt;/p&gt;
&lt;p&gt;我们韩国有句俗话：像狗一样挣钱，像宰相一样花钱。我认为现在应该是”像宰相一样挣钱，也像宰相一样花钱“。干净合法地挣钱，正大光明地花钱，这才是健康地社会。&lt;/p&gt;
</content:encoded></item><item><title>《经营未来》精选-1</title><link>https://lllirunze.cn/posts/reading-9787010068725-1/</link><guid isPermaLink="true">https://lllirunze.cn/posts/reading-9787010068725-1/</guid><description>年轻意味着什么？意味着即使失败，也随时可以再挑战。</description><pubDate>Sat, 22 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;自小就有的梦想，一生都在我心中澎湃；&lt;/p&gt;
&lt;p&gt;我喜欢冒险与挑战所带来的热情与振奋，我一直梦想社会安定、经济安乐以及透过文化而获得快乐的”幸福世界“。&lt;/p&gt;
&lt;p&gt;我要成为”自己的主人“、”良心的主人”和“事业的主人”。&lt;/p&gt;
&lt;p&gt;从一个清理垃圾卖苦力的工读学生，到敢于迎接挑战的学生会主席，到军事政权的反抗者，到打工者，到职业经理人，到首尔市长，到当选总统，是贫困教会了我善于学习、教会了我冷静地思考人生和社会地意义；迫使我执意进取，直面挑战，勇于变革；更让我懂得了把握未来、经营未来的重要。&lt;/p&gt;
&lt;p&gt;人必有所守护，方能有所坚持。我贯彻一生要为国民幸福坚持奋力拼搏；我愿意在任何危机、挑战面前，毅然迎上前去；我坚持再苦、再难也要堂堂正正地做人。这是在经历了艰难的成长、求学、事业开拓之后，珍藏于内心的一个坚定信念。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;李明博&lt;br /&gt;
2008年2月&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;妈妈，请让我上高中吧！&lt;/h2&gt;
&lt;p&gt;在我即将从浦项中学毕业的时候，家里的处境更加困难了。大哥已经参军，二哥从同志商业高中毕业后考上了一所免学费的陆军军官学校，但因为身体原因退了学，只得重新准备考大学。我知道家里根本没钱供我继续念高中，便把升学的念头抛在一边。但是，我们的班主任却无论如何也不想放弃我。&lt;/p&gt;
&lt;p&gt;毕业前，学校召开了升学讨论会。按照已往的情况，浦项中学的优秀毕业生都能进入庆北高中等名校。班主任认为，成绩一直名列全校第二的我肯定能考入好学校，因此让我的家长务必去一趟学校，商量我的升学问题。那时候，母亲刚开始卖红豆烤饼，从一大早忙到大半夜，根本没有时间来学校。在她看来，拼命赚钱为二哥筹学费是第一要紧的事。&lt;/p&gt;
&lt;p&gt;但我还是抱着提一下的想法，向母亲传达了班主任的意思。母亲默默地做着红豆烤饼，好一会，她看着远方对我说：&lt;/p&gt;
&lt;p&gt;“咱们家这个情况，你是不可能上高中的。如果你二哥落榜了，你还可以去试一试。如果一定要上高中，那也只能上免学费的邮政高中。可一要是一走，谁帮我做这个生意啊？我一个人可忙不过来。”&lt;/p&gt;
&lt;p&gt;虽然早知道结果，可听母亲这么一字一句说出来，泪水还是忍不住在眼眶里打转。&lt;/p&gt;
&lt;p&gt;班主任知道我家的情况后，又给我出了一个主意：&lt;/p&gt;
&lt;p&gt;“你不上高中的话，真是太可惜了……对了，浦项同志商业高中有个夜校。你可以白天帮家里干活，晚上再去念书。你现在还小，可能不知道，以后要找工作的话，高中毕业证可比初中毕业证有用多了。”&lt;/p&gt;
&lt;p&gt;我满怀期望地跟母亲说了班主任的建议，可母亲还是不同意。&lt;/p&gt;
&lt;p&gt;“你得帮我做生意，帮哥哥挣学费。生意做得好，也一样可以过上好日子。再说，上夜校也是要钱的，我们家可实在拿不出你的学费啊。”&lt;/p&gt;
&lt;p&gt;好心的班主任还在执著地跟母亲进行“攻防持久战”。两边传话的我也累得够呛。&lt;/p&gt;
&lt;p&gt;“全部课程都拿第一的学生可以免学费，我相信明博可以做到。”&lt;/p&gt;
&lt;p&gt;终于，班主任的最后一个提议被母亲接受了。&lt;/p&gt;
&lt;p&gt;“这样的话，咱们做个约定好了。我同意你去上夜校，但前提是不用家里出学费。只能靠你自己努力了。”&lt;/p&gt;
&lt;p&gt;因为这个约定，我一直读到了高中毕业。三年夜校，我每门课的成绩都是第一名。&lt;/p&gt;
&lt;p&gt;上高中后，我开始随着季节变化做买卖：春天卖麦芽糖，夏天卖冰棍儿，冬天卖爆米花儿。&lt;/p&gt;
&lt;p&gt;不管晴天下雨，我总穿着同一件校服，因为穿得出门的衣服就这么一件。我做买卖的那条街上总有许多女校学生来来往往，我的破旧校服、脏兮兮的脸、低着头傻乎乎的样子都成了她们取笑的对象。我不停地对自己说要泰然处之，但强烈的自尊心，加上内向的性格、青春期的焦虑，我又如何做到泰然处之？&lt;/p&gt;
&lt;p&gt;思来想去，只好拿顶草帽一遮了事。&lt;/p&gt;
&lt;p&gt;到高二时，我决定尝试着做水果生意，一来赚钱比较多，二来也可以躲避那些女生的异样眼光。我白天去市场进水果，晚上放学后推到热闹的剧院门口去卖。刚开始颇有些紧张。我把水果擦得亮亮的，还准备了一盏炭化灯。有一天夜里下着雨，路上行人不多。我正巴巴地盯着剧院门口，盼望电影散场后能有人光顾我的水果摊，突然，有辆小汽车在倒车时撞倒了我的推车，车上的水果咕噜噜撒了一地，几个西瓜都摔烂了。我连忙冲过去捡我的水果，这时，一个声音冲我骂了起来：&lt;/p&gt;
&lt;p&gt;“喂，臭小子，推车就好好推，干吗停在中间拦道？你以为这路时你们家的吗？”&lt;/p&gt;
&lt;p&gt;我一时慌了神，赶紧向他道歉；可等到那车开走以后，我突然觉得很愤怒。其实我做错了什么了呢？这样被人欺负，感觉真窝囊。想到贫穷带来的屈辱，悲伤、委屈、愤怒一股脑儿涌上心头。&lt;/p&gt;
&lt;p&gt;“这么活着有什么意思？就算高中毕业又能怎样？干脆离开这个鬼地方算了！”&lt;/p&gt;
&lt;p&gt;这么恨恨地想着，掏出口袋里地钱数了数，足够去首尔地路费了。我偷偷擦干眼泪，走进了路边的小吃摊，想在出发前喝点酒。&lt;/p&gt;
&lt;p&gt;“大婶，给我一瓶烧酒，一碟小菜！”我大声喊道。&lt;/p&gt;
&lt;p&gt;“今天这孩子怎么了？”&lt;/p&gt;
&lt;p&gt;一向看我很乖的大婶吃了一惊。&lt;/p&gt;
&lt;p&gt;“快点上酒啊，怎么这么多话！给你钱就是了。”&lt;/p&gt;
&lt;p&gt;我开始发脾气，可大婶还是磨磨蹭蹭地没给我拿酒。就在等待地几秒钟里，我突然想起一件事：&lt;/p&gt;
&lt;p&gt;”卖了这么长时间地水果，还没有让妈妈尝过我的水果呢。“&lt;/p&gt;
&lt;p&gt;每次我从市场进水果回来，母亲总是一边擦着水果，一边说：”这些水果真漂亮啊，一看就知道很好吃。“但是把这些都视为独立财产地我，抱着即使一分钱也要节约的心，总是假装没有听见母亲的话。&lt;/p&gt;
&lt;p&gt;”是啊，又不是非要今天走。水果虽然撞烂了，但还是可以让妈妈好好吃个够。那就明天再走吧，晚一天也没关系。“这么打定了主意，我把水果重新装上车，推回了家。&lt;/p&gt;
&lt;p&gt;”爸，妈，今天吃点水果吧，剩了很多呢。“&lt;/p&gt;
&lt;p&gt;母亲看见被撞歪的拖车和摔碎的西瓜，还有我夸张的喊声，大约知道了发生的事情。她一句话也没说，转身进了被窝。那天夜里我躺在睡铺上，满脑子想的都是离家出走。&lt;/p&gt;
&lt;p&gt;第二天清晨，母亲照例开始起到，但那一天，她给我的祈祷格外地长，似乎她也一夜没睡好。&lt;/p&gt;
&lt;p&gt;”祈求上帝为我们家明博指引一条光明的路，让他健康成长，让他做每一件事都顺顺利利……“&lt;/p&gt;
&lt;p&gt;母亲的祈祷撞击着我的心。”原来，母亲是这样地关心着我啊！“感激地心情促使我将离家出走地计划又推迟了一个月。这样反复几次之后，我又恢复成了原先那个穿着校服、买水果的我。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/images/posts/reading/Snipaste_2025-02-23_23-33-53.png&quot; alt=&quot;pic1&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;蜕变&lt;/h2&gt;
&lt;p&gt;我在戒严司令部受到盘问。为了要我交代他们需要的情况，他们用各种方法胁迫我，用得最多的是不让我睡觉。&lt;/p&gt;
&lt;p&gt;“小子，我们可以把你塞进冷冻室，也可以把你扔进海里，如果你不想‘意外死亡’，最好乖乖交代！”&lt;/p&gt;
&lt;p&gt;我始终咬紧牙关。我得遵守诺言。&lt;/p&gt;
&lt;p&gt;审判时我们被转到了地方法庭。出庭时，在野党的政界人士以及宗教界、法律界、文化界人士，还有学生都给予了我们坚定的支持。我们仿佛成了英雄。&lt;/p&gt;
&lt;p&gt;最终，和其他“主谋者”差不多，我被判处5年有期徒刑，关押在西大门监狱。我所在的牢房里有杀人犯、强奸犯、诈骗犯等等，平时这些人都以讲述自己的“传奇故事”打发时间。学生罪犯则把监狱当做另外一片斗争天地开展绝食运动。进行反专制斗争的人也想通过把我们捧成英雄来突破当时的斗争困境。但说实话，我始终觉得我们所做的一切，与那些独立斗士、爱国志士相比，根本算不了什么。这只是年轻一代应当为国家所尽的义务，不能将其夸大为英雄主义。&lt;/p&gt;
&lt;p&gt;我突然明白了自己在狱中应该做些什么：作为学生，我要把这段时间落下的功课补回来。我一边拼命读书，一边开始冷静地思考人生和社会的意义。&lt;/p&gt;
&lt;p&gt;西大门的监狱生活从1964年6月末开始，于10月末结束。法院改判我3年有期徒刑，缓期5年执行。如今回头看，这段生活对我而言，不啻为一种幸运。我在监狱中学会了乐观。在那以前，我一直以为自己生活在最底层、经历过无可比拟的绝望。但是在狱中，我懂得了所谓悲观与乐观都是相对的。在监狱外的人看来，被囚禁之人都是极端悲惨的；但对死刑犯而言，只要活着就是莫大的幸福。艰苦的狱中生活还让我领悟到了人身上潜在的超强的适应能力。刚开始，每天早上分到的水连湿手都不够；一个月后，用那点水完全可以洗手、洗脸。&lt;/p&gt;
&lt;p&gt;从当选学生会主席，到逃亡、坐牢，这一年的经历让我从幼虫蜕变成了长着翅膀的成虫！&lt;/p&gt;
&lt;p&gt;出狱后，我发现自己一下子成了名人。&lt;/p&gt;
&lt;p&gt;有一天，我突然收到从外婆家寄来的一箱苹果。箱子上的收件人地址让我永远难忘：&lt;/p&gt;
&lt;p&gt;“首尔市龙山区，李明博收”&lt;/p&gt;
&lt;p&gt;因为穷困，我们几乎和外婆家没什么联系。怎么突然出现这么一箱苹果呢？后来才知道，在看到我被释放的报道后，外婆她们想寄些苹果来慰问，可又不知道详细地址，只大约记得我们在首尔龙山的某个地方。这箱地址不详的苹果居然能顺利到达我家，可见我当时多么有名了。&lt;/p&gt;
&lt;p&gt;但这时，母亲的身体因过度操劳，完全垮了。&lt;/p&gt;
&lt;p&gt;从日本回来后的二十多年里，母亲没有睡过一天安稳觉，身体自然每况愈下。我在监狱的时候，母亲来探望我一次。我一看到母亲就知道她病得不轻，可她却努力装出不要紧的样子。那天，母亲直视我的眼睛，说：&lt;/p&gt;
&lt;p&gt;“明博，我一直以为你是个不起眼的小东西，现在才发现，你才是真正了不起的家伙。你的想法是对的，以后就按照自己的信念去做吧，我会为你祈祷的。”&lt;/p&gt;
&lt;p&gt;这是母亲第一次，也是最后一次肯定我。&lt;/p&gt;
&lt;p&gt;等到我出狱的时候，母亲已经卧床不起。那年的12月15日，母亲永远地离开了我们。&lt;/p&gt;
&lt;p&gt;父亲在京畿道利川度过了他的余生。大哥为父亲准备了一个小农场，父亲一到农场就把母亲移葬过去，并亲自为母亲立了碑铭：&lt;/p&gt;
&lt;p&gt;“你千辛万苦把孩子们拉扯大，却没能看到孩子们成功，留下我一人享尽天伦，实在让我惭愧。”&lt;/p&gt;
&lt;p&gt;父亲是在1981年我当现代建设社长地时候去世地。和母亲一样，都是在12月。&lt;/p&gt;
</content:encoded></item><item><title>JS Introductory Basics</title><link>https://lllirunze.cn/posts/js-guide/</link><guid isPermaLink="true">https://lllirunze.cn/posts/js-guide/</guid><description>Master key concepts of JS, functions, event handling and other technologies.</description><pubDate>Fri, 21 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;JavaScript&lt;/strong&gt;是一种轻量级、解释型、面向对象的脚本语言。它主要用于网页开发，能够在网页上实现动态效果，增强用户与网页的交互体验。&lt;/p&gt;
&lt;p&gt;作为一种客户端脚本语言，JS可以直接嵌入HTML，并在浏览器中执行，使得网页不再是静态的，而是可以根据用户操作动态变化。&lt;/p&gt;
&lt;h2&gt;JavaScript的应用场景&lt;/h2&gt;
&lt;p&gt;JavaScript 主要用于以下几个方面：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;客户端脚本&lt;/strong&gt;：在浏览器端执行，实现动态效果和用户交互。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网页开发&lt;/strong&gt;：与HTML和CSS结合，使网页更具交互性和动态性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;后端开发&lt;/strong&gt;：通过Node.js，JavaScript也可以在服务器端运行，实现后端应用开发。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(&quot;Hello JavaScript!&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;JavaScript基础语法&lt;/h2&gt;
&lt;h3&gt;变量声明&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;var x;                  // 变量，具有函数作用域
let y = 5;              // 变量，具有块级作用域，更安全灵活
const pi = 3.14;        // 常量
console.log(x, y, pi);  // 输出: undefined 5 3.14 (undefined表示已被声明但未赋值)

let name = &apos;lllirunze&apos;;
console.log(name);

let empty_value = null;
console.log(empty_value); // 输出: null，表示明确为空
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;条件判断与循环&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;if (condition1) {
    // code
} else if (condition2) {
    // code
} else {
    alert(&quot;error: xxx&quot;);
}

for (let i = 0; i &amp;lt; 10; i++) {
    console.log(i);
}

let count = 1;
while (count &amp;lt;= 10) {
    console.log(count);
    count++;
}

// break语句用于终止循环
// continue语句用于跳过当前循环的剩余部分，直接进入下一次循环
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;function functionName(param1, param2) { 
    return param1 + param2;
}

let result = functionName(3, 5);
console.log(result); // 输出: 8
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;变量作用域&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;let global_var = &apos;global variable&apos;;
function localVarFunction() {
    let local_var = &apos;local variable&apos;;
    console.log(&apos;global variable:&apos; + global_var);
    console.log(&apos;local  variable:&apos; + local_var);
}

localVarFunction();
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;事件（Events）&lt;/h2&gt;
&lt;p&gt;事件是文档或浏览器窗口中发生的特定瞬间，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;onClick&lt;/code&gt;：点击事件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onMouseOver&lt;/code&gt;：鼠标悬停&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onMouseOut&lt;/code&gt;：鼠标移出&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onChange&lt;/code&gt;：文本内容改变&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onSelect&lt;/code&gt;：文本框选中&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onFocus&lt;/code&gt;：输入框获得焦点&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onBlur&lt;/code&gt;：输入框失去焦点&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;JavaScript绑定事件有三种方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;HTML属性方式&lt;/li&gt;
&lt;li&gt;DOM属性方式&lt;/li&gt;
&lt;li&gt;&lt;code&gt;addEventListener&lt;/code&gt; 方式&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;script&amp;gt;
    function clickEvent() {
        alert(&apos;点击事件触发了&apos;);
    }
    function focusEvent() {
        console.log(&apos;获取焦点&apos;);
    }
    function blurEvent() {
        console.log(&apos;失去焦点&apos;);
    }
&amp;lt;/script&amp;gt;

&amp;lt;button onclick=&quot;clickEvent()&quot;&amp;gt;click button&amp;lt;/button&amp;gt;
&amp;lt;input type=&quot;text&quot; onfocus=&quot;focusEvent()&quot; onblur=&quot;blurEvent()&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;文档对象模型（DOM）&lt;/h2&gt;
&lt;p&gt;当网页被加载时，浏览器会创建DOM，将HTML结构解析为树形结构。DOM提供了一个编程接口，允许开发者通过JavaScript操作网页元素。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/images/posts/js/image-20250122231608774.png&quot; alt=&quot;dom-tree&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;获取DOM元素&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;var elementById = document.getElementById(&apos;box1&apos;);                // 通过 id 获取元素
var elementByClass = document.getElementsByClassName(&quot;box2&quot;)[0];  // 通过 class 获取元素
var elementByTag = document.getElementsByTagName(&apos;div&apos;);          // 通过标签名获取元素
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;修改元素内容&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;elementById.innerHTML = &apos;edit html content&apos;;  // 解析HTML
elementByClass.innerText = &apos;edit text&apos;;       // 仅修改文本
elementByTag.style.color = &apos;red&apos;;             // 修改元素样式
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;绑定事件&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;var buttonElement = document.getElementsByTagName(&apos;button&apos;)[0];

// 方式1：直接绑定onclick事件
buttonElement.onclick = function() {
    alert(&apos;Click events triggered by DOM.&apos;);
};

// 方式2：使用addEventListener绑定事件
buttonElement.addEventListener(&apos;click&apos;, function() {
    alert(&apos;Trigger the click event by addEventListener.&apos;);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;:::note[Reference]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1BT4y1W7Aw&quot;&gt;3小时前端入门教程（HTML+CSS+JS）&lt;/a&gt;
:::&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Python Crawler</title><link>https://lllirunze.cn/posts/web-crawler/</link><guid isPermaLink="true">https://lllirunze.cn/posts/web-crawler/</guid><description>This blog will cover how to write an efficient web crawler using Python.</description><pubDate>Thu, 13 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;什么是爬虫？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Python爬虫&lt;/strong&gt;是一种利用Python编程语言编写的程序，目的是从互联网上自动获取信息。这些信息可以是网页内容、图片、视频或者其他类型的数据。Python爬虫通过模拟浏览器的行为，访问网页并提取所需的数据，然后将数据保存或进一步处理，以供后续分析或使用。常见的Python爬虫库包括Beautiful Soup和Scrapy等，它们使得爬取网页数据变得更加高效和方便。&lt;/p&gt;
&lt;p&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;/ol&gt;
&lt;p&gt;爬虫需要注意一些事项：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不要爬取公民隐私数据&lt;/li&gt;
&lt;li&gt;不要爬取受著作权保护的内容&lt;/li&gt;
&lt;li&gt;不要爬取涉及到country事务，建设等&lt;/li&gt;
&lt;li&gt;爬虫的请求数量和频率不要过高&lt;/li&gt;
&lt;li&gt;网站如果存在反爬限制，请不要强行爬取&lt;/li&gt;
&lt;li&gt;可以通过查看网站的&lt;code&gt;robots.txt&lt;/code&gt;文件，了解可爬取的网页路径范围，该文件指明了哪些网页允许被爬取&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;{% note red fa-triangle-exclamation %}请遵守以上内容，这样可以更好更礼貌地使用python爬虫。{% endnote %}&lt;/p&gt;
&lt;h2&gt;HTTP请求和响应&lt;/h2&gt;
&lt;p&gt;HTTP请求和响应是Web开发中非常重要的概念，用于客户端（例如浏览器）和服务器之间的通信。&lt;/p&gt;
&lt;p&gt;HTTP有不同的请求方法，常见的有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GET：获得数据&lt;/li&gt;
&lt;li&gt;POST：创建数据&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;HTTP请求由三部分组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;请求行：包含方法类型，资源路径和协议版本&lt;/li&gt;
&lt;li&gt;请求头：包含关于请求的元数据，如内容类型、认证信息等&lt;/li&gt;
&lt;li&gt;请求体：对于某些请求方法（如POST），可能包含发送到服务器的数据，比如表单数据或JSON数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;HTTP响应由三部分组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;状态行：指示服务器&lt;a href=&quot;https://javaguide.cn/cs-basics/network/http-status-codes.html&quot;&gt;对请求的处理结果&lt;/a&gt;，如200表示成功，404表示未找到请求的资源等&lt;/li&gt;
&lt;li&gt;响应头：包含关于响应的元数据，如内容类型、缓存控制信息等&lt;/li&gt;
&lt;li&gt;响应体：包含实际请求的数据，如HTML文档、JSON数据或者其他类型的内容&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;如何用Python Requests发送请求？&lt;/h2&gt;
&lt;p&gt;首先打开终端，安装相关库，输入如下指令即可安装成功。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pip install requests
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们输入如下内容，进行对某网站http请求，得到如下结果。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import requests

headers = {
  &quot;user-agent&quot;: &quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36&quot;,
}

response = requests.get(&quot;http://lllirunze.cn/&quot;, headers=headers)
print(response)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Response [200]&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果我们&lt;code&gt;print(response.text)&lt;/code&gt;的话，会输出该页面的html代码，看起来会比较复杂。&lt;/p&gt;
&lt;p&gt;在进行爬取的时候，建议添加一些headers内容，使用它的目的是为了模拟浏览器发送请求，这样可以让请求看起来像是通过正常浏览器发出的，而不是由脚本或爬虫发出的。这对于一些反爬虫机制可能会有所帮助，避免被网站认为是机器人访问，从而减少被封禁或限制访问的风险。&lt;/p&gt;
&lt;h2&gt;HTML网页结构&lt;/h2&gt;
&lt;p&gt;HTML网页结构是用来定义网页内容的语言，它通过标签&lt;code&gt;tags&lt;/code&gt;来组织和显示文本、图像、链接等信息。一个HTML网页通常由多个元素组成，这些元素按照一定的规则嵌套在一起，形成页面的结构。&lt;/p&gt;
&lt;p&gt;可以看&lt;a href=&quot;https://lllirunze.cn/2025/01/24/HTML-Introductory-Basics/#Common-Text-Tags&quot;&gt;前文&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;如何用Beautiful Soup解析HTML内容？&lt;/h2&gt;
&lt;p&gt;首先在终端输入指令安装对应库。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pip install bs4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以爬取&lt;a href=&quot;https://books.toscrape.com/&quot;&gt;Books to Scrape&lt;/a&gt;所有书名为例，通过在该网站点击F12，我们可以找到所有书名对应的代码块为h3标签，因此我们可以使用如下代码即可爬取到该网页的书名。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import requests
from bs4 import BeautifulSoup

headers = {
  &quot;user-agent&quot;: &quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36&quot;,
}

content = requests.get(&quot;https://books.toscrape.com/&quot;, headers=headers).text
soup = BeautifulSoup(content, &quot;html.parser&quot;)
all_titles = soup.findAll(&quot;h3&quot;)

for title in all_titles:
  link = title.find(&quot;a&quot;)
  print(link.string)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/images/posts/crawler/Snipaste_2025-02-13_21-34-39.png&quot; alt=&quot;books&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;:::note[Reference]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://scrapfly.io/blog/crawling-with-python/&quot;&gt;How to Crawl the Web with Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1d54y1g7db&quot;&gt;【Python+爬虫】爆肝两个月！拜托三连了！这绝对是全B站最用心（没有之一）的Python+爬虫公开课程，从入门到（不）入狱 ！&lt;/a&gt;
:::&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>What is Neofetch?</title><link>https://lllirunze.cn/posts/neofetch/</link><guid isPermaLink="true">https://lllirunze.cn/posts/neofetch/</guid><description>Display detailed information about operating system from the command line.</description><pubDate>Sat, 08 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Neofetch&lt;/strong&gt;是一款用 bash 3.2+ 编写的命令行系统信息工具。Neofetch能以美观、视觉愉悦的方式显示操作系统、软件和硬件的相关信息。用户可以快速查看关于操作系统、内核版本、桌面环境、硬件配置等的详细信息。&lt;/p&gt;
&lt;h2&gt;Neofetch的主要特点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;跨平台支持&lt;/strong&gt;：Neofetch支持Linux、macOS和Windows（通过WSL）等多种操作系统。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;美观的输出&lt;/strong&gt;：Neofetch在终端中以整洁且富有美感的方式展示系统信息，包含了诸如操作系统名称、内核版本、CPU、内存、磁盘等信息，还会显示一个彩色的操作系统logo。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;高度可定制&lt;/strong&gt;：用户可以根据自己的需求来定制Neofetch输出的信息，甚至可以修改显示的顺序和颜色主题。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;轻量化设计&lt;/strong&gt;：Neofetch是一个非常轻量的工具，启动速度极快，占用的系统资源非常低，非常适合在资源有限的环境中使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Neofetch显示的信息内容&lt;/h2&gt;
&lt;p&gt;默认情况下，Neofetch会显示以下系统信息：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;操作系统名称及其版本&lt;/li&gt;
&lt;li&gt;内核版本&lt;/li&gt;
&lt;li&gt;当前的桌面环境或窗口管理器&lt;/li&gt;
&lt;li&gt;CPU 型号及其核心数&lt;/li&gt;
&lt;li&gt;其他&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;如何使用Neofetch&lt;/h2&gt;
&lt;p&gt;以Ubuntu Linux为例，使用如下命令进行安装。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get update
sudo apt-get install neofetch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装完毕之后，直接在终端中输入&lt;code&gt;neofetch&lt;/code&gt;的命令就可以了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/images/posts/neofetch/Snipaste_2025-02-08_16-48-31.png&quot; alt=&quot;neofetch&quot; /&gt;&lt;/p&gt;
&lt;p&gt;如果我们希望在进入终端的时候直接获得Neofetch的信息，我们可以进行如下配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 打开配置文件
vim ~/.bashrc
# 在文件的最后一行添加如下信息：
neofetch
# 保存并退出之后，使修改生效
source ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重启进入终端就可以直接获取Neofetch的信息了。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;:::note[Reference]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dylanaraps/neofetch&quot;&gt;neofetch&lt;/a&gt;
:::&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>TJU Course Sharing Project</title><link>https://lllirunze.cn/posts/tju-courses-sharing/</link><guid isPermaLink="true">https://lllirunze.cn/posts/tju-courses-sharing/</guid><description>分享：天津大学课程共享计划。</description><pubDate>Wed, 05 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::tip
感谢项目作者&lt;a href=&quot;https://github.com/superpung&quot;&gt;superpung&lt;/a&gt;。
:::&lt;/p&gt;
&lt;p&gt;随着大学学习的深入，我们往往会面临课程资料的收集与整理问题。从选课到复习，从课程资料到历年试卷，所有这些内容都需要花费大量的时间与精力去查找和整理。为了帮助更多的同学们减少这种重复劳动、提高学习效率，&lt;a href=&quot;https://cs.tjuse.com/&quot;&gt;&lt;strong&gt;天津大学课程共享计划&lt;/strong&gt;&lt;/a&gt;应运而生。&lt;/p&gt;
&lt;p&gt;天津大学课程共享计划，灵感来源于&lt;a href=&quot;https://github.com/QSCTech/zju-icicles&quot;&gt;浙江大学课程攻略共享计划&lt;/a&gt;，旨在通过一个集中平台，收集并分享天津大学的各类课程资料和经验，打破传统的依赖学长学姐口口相传的方式，让所有学生能够便捷地访问有用的学习资源。&lt;/p&gt;
&lt;h2&gt;项目背景&lt;/h2&gt;
&lt;p&gt;回忆大学生活，每一门课程的学习都离不开各类资料的帮助。可是在忙碌的学期中，很多同学常常因为资料散落在不同的地方而错过重要信息。天津大学课程共享计划的初衷正是解决这种信息不对称和资源不易获取的问题。通过集中管理和公开分享课程资料，让后来的学生不必再走弯路，把前人的经验传递给更多的人。&lt;/p&gt;
&lt;h2&gt;项目内容&lt;/h2&gt;
&lt;ul&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;/ul&gt;
&lt;p&gt;天津大学课程共享计划不仅仅是一个资料共享平台，它是一个为天津大学学子提供支持的社区。通过每个学生的贡献和参与，未来平台的内容会越来越丰富，资源的质量会逐步提高，最终实现一个开放、高效和共享的学习环境。&lt;/p&gt;
&lt;p&gt;如果你是天津大学的同学，或者对这个项目有兴趣，欢迎访问天津大学课程共享计划并贡献自己的力量！&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;::github{repo=&quot;superpung/TJU-CourseSharing&quot;}&lt;/p&gt;
</content:encoded></item><item><title>Git Guides</title><link>https://lllirunze.cn/posts/git-guide/</link><guid isPermaLink="true">https://lllirunze.cn/posts/git-guide/</guid><description>From beginners to advanced, learn how to effectively manage code versions, collaborate on development.</description><pubDate>Fri, 31 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Git&lt;/strong&gt;是一个分布式版本控制系统，它能够帮助我们管理代码历史记录，并且支持多人协作开发。在软件开发中，使用Git来管理版本和协作开发已经成为了标准实践。本文列举了一些常用的Git操作。&lt;/p&gt;
&lt;h2&gt;安装Git&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Windows：&lt;a href=&quot;https://git-scm.com/downloads&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ubuntu Linux：&lt;code&gt;sudo apt-get install git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;CentOS Linux：&lt;code&gt;sudo yum install git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;MacOS：&lt;code&gt;brew install git&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;配置Git&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;git config --global user.name &quot;xxx&quot;           # 配置用户名
git config --global user.email &quot;xxx@xxx.xxx&quot;  # 配置邮箱
git config --global color.ui true             # 配置颜色
git config --global core.editor vim           # 配置git使用的编辑器，以vim为例
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Git常用操作&lt;/h2&gt;
&lt;h3&gt;创建Git仓库&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git init
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;克隆现有仓库&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git clone git@github.com:lllirunze/lllirunze.git
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;查看仓库状态&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git status
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;添加文件到暂存区&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git add &amp;lt;file&amp;gt;  # (1)添加指定文件
git add .       # (2)添加所有文件
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;提交更改&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git commit          # (1)打开指定编辑器，编写提交内容
git commit -m &quot;xxx&quot; # (2)直接将xxx的提交内容添加到暂存区
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;查看提交历史&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git log
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;版本回退&lt;/h3&gt;
&lt;p&gt;我们通过&lt;code&gt;git log&lt;/code&gt;找到要回退的版本后，根据对应的&lt;code&gt;commit id&lt;/code&gt;，执行如下操作（版本号不用写全，写前几位就行了）。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git reset &amp;lt;commit id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Git分支管理&lt;/h2&gt;
&lt;h3&gt;查看目前所在分支&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git branch
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;创建新分支&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git branch &amp;lt;new branch&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;切换分支&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git checkout &amp;lt;branch&amp;gt;         # (1) 切换到已有分支
git checkout -b &amp;lt;new-branch&amp;gt;  # (2) 创建新分支并切换至此
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;合并分支&lt;/h3&gt;
&lt;p&gt;在一个分支上完成工作后，我们先切换回主分支上再进行&lt;code&gt;merge&lt;/code&gt;操作。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git checkout &amp;lt;main-branch&amp;gt;
git merge &amp;lt;other-branch&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;删除分支&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git branch -d &amp;lt;branch&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;远程仓库操作&lt;/h2&gt;
&lt;p&gt;在添加远程仓库之前（以GitHub为例），我们需要为本机创建SSH key，并将其粘贴到GitHub账户中。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh-keygen -t rsa -C &quot;xxx@xxx.xxx&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一路回车获取默认值就行。后续我们可以在用户主目录中找到&lt;code&gt;.ssh&lt;/code&gt;目录，里面有&lt;code&gt;id_rsa&lt;/code&gt;和&lt;code&gt;id_rsa.pub&lt;/code&gt;两个文件。我们将&lt;code&gt;id_rsa.pub&lt;/code&gt;中的内容复制到GitHub的SSH密钥配置界面中即可。&lt;/p&gt;
&lt;p&gt;:::tip
GitHub主页-&amp;gt;点击右上角头像-&amp;gt;Settings-&amp;gt;SSH and GPG keys-&amp;gt;New SSH key
:::&lt;/p&gt;
&lt;h3&gt;为本地添加远程仓库&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git remote add origin git@github.com:lllirunze/lllirunze.git
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;查看当前配置的远程仓库&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git remote -v
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;推送到远程仓库&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git push &amp;lt;remote branch&amp;gt; &amp;lt;local branch&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一般来说，&lt;code&gt;origin&lt;/code&gt;为远程仓库的默认名称，&lt;code&gt;&amp;lt;local branch&amp;gt;&lt;/code&gt;是我们推送的分支名。&lt;/p&gt;
&lt;h3&gt;拉取远程仓库的最新内容&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git pull origin &amp;lt;local branch&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;删除远程仓库的链接&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git remote remove origin
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;:::note[Reference]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://liaoxuefeng.com/books/git/&quot;&gt;Git教程-廖雪峰的官方网站&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.github.com/training-kit/&quot;&gt;GitHub Training Kit&lt;/a&gt;
:::&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>NJU ICS PA1</title><link>https://lllirunze.cn/posts/nju-ics-pa1/</link><guid isPermaLink="true">https://lllirunze.cn/posts/nju-ics-pa1/</guid><description>南京大学计算机科学与技术系计算机系统基础课程实验-PA1</description><pubDate>Thu, 30 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;选择实现架构：&lt;code&gt;riscv32&lt;/code&gt;&lt;/h3&gt;
&lt;h2&gt;单步执行&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;// nemu\src\monitor\sdb\sdb.c
static int cmd_si(char *args) {
  char *str = strtok(args, &quot; &quot;);
  if (str == NULL) cpu_exec(1);
  else {
    uint64_t step = strtoul(str, NULL, 10);
    cpu_exec(step);
  }
  return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;打印寄存器&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;// nemu\src\monitor\sdb\sdb.c
static int cmd_info(char *args) {
  isa_reg_display();
  return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;// nemu\src\isa\riscv32\reg.c
void isa_reg_display() {
  int reg_num = ARRLEN(cpu.gpr);
  int i;
  for (i = 0; i &amp;lt; reg_num; i++) {
    printf(&quot;%s\t0x%08x\t%u\n&quot;, reg_name(i), gpr(i), gpr(i));
  }
  printf(&quot;pc\t0x%08x\t%u\n&quot;, cpu.pc, cpu.pc);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;扫描内存&lt;/h2&gt;
&lt;p&gt;先实现一个简单的版本：规定表达式&lt;code&gt;expr&lt;/code&gt;中只能是一个十六进制数&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// nemu\src\monitor\sdb\sdb.c
static int cmd_x(char *args) {
  char *str = strtok(NULL, &quot; &quot;);
  int N = atoi(str);
  char *expr = strtok(NULL, &quot; &quot;);
  expr = expr + 2;
  vaddr_t src = (vaddr_t)strtoul(expr, NULL, 16);

  int i;
  for (i = 0; i &amp;lt; N; i++) {
    word_t addr = vaddr_read(src + i * 4, 4);
    if (i % 4 == 0) printf(&quot;0x%08x:\t&quot;, src + i * 4);
    printf(&quot;0x%08x&quot;, addr);
    if (i % 4 == 3) printf(&quot;\n&quot;);
    else printf(&quot;\t&quot;);
  }
  if (N % 4 != 0) printf(&quot;\n&quot;);

  return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;算术表达式的词法分析&lt;/h2&gt;
&lt;p&gt;我们在实现的过程中需要注意一件事情，运算符是存在计算优先级的，可以参考&lt;a href=&quot;https://blog.csdn.net/sunshihua12829/article/details/47912123&quot;&gt;link&lt;/a&gt;。我们调整&lt;code&gt;struct rule&lt;/code&gt;类型的结构，添加一个变量priority。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// nemu\src\monitor\sdb\expr.c
struct rule {
  const char *regex;
  int token_type;
  int priority;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们根据正则表达式对token类型添加匹配规则：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// nemu\src\monitor\sdb\expr.c
static struct rule rules[] = {
  {&quot; +&quot;, TK_NOTYPE, 0},             // spaces
  {&quot;\\+&quot;, &apos;+&apos;, 4},                  // plus
  {&quot;-&quot;, &apos;-&apos;, 4},                    // minus OR negation
  {&quot;\\*&quot;, &apos;*&apos;, 3},                  // multiplication OR dereference
  {&quot;\\/&quot;, &apos;/&apos;, 3},                  // division
  {&quot;\\%&quot;, &apos;%&apos;, 3},                  // mod
  {&quot;\\(&quot;, &apos;(&apos;, 1},                  // left parenthesis
  {&quot;\\)&quot;, &apos;)&apos;, 1},                  // right parenthesis
  {&quot;0[xX][0-9a-fA-F]+&quot;, TK_HEX, 0}, // hexadecimal number -&amp;gt; 0x..(0)
  {&quot;[0-9]+&quot;, TK_DEC, 0},            // decimal number
  {&quot;\\$(0|ra|sp|gp|tp|t[0-6]|s10|s11|s[0-9]|a[0-7]|pc)&quot;, TK_REG, 0}, // registers
  {&quot;==&quot;, TK_EQ, 7},                 // equal
  {&quot;!=&quot;, TK_NEQ, 7},                // not equal
  {&quot;&amp;amp;&amp;amp;&quot;, TK_AND, 11},               // and
  {&quot;\\|\\|&quot;, TK_OR, 12},            // or
  {&quot;!&quot;, &apos;!&apos;, 2},                    // not
  {&quot;&amp;amp;&quot;, &apos;&amp;amp;&apos;, 8},                    // bitwise and (we don&apos;t consider taking address)
  {&quot;\\|&quot;, &apos;|&apos;, 10},                 // bitwise or
  {&quot;\\^&quot;, &apos;^&apos;, 9},                  // bitwise xor
  {&quot;~&quot;, &apos;~&apos;, 2},                    // bitwise inversion
  {&quot;&amp;lt;&amp;lt;&quot;, TK_SHIFTLEFT, 5},          // shift left
  {&quot;&amp;gt;&amp;gt;&quot;, TK_SHIFTRIGHT, 5},         // shift right
  {&quot;&amp;gt;=&quot;, TK_GEQ, 6},                // greater than or equal to
  {&quot;&amp;lt;=&quot;, TK_LEQ, 6},                // less than or equal to
  {&quot;&amp;gt;&quot;, TK_G, 6},                   // greater than
  {&quot;&amp;lt;&quot;, TK_L, 6},                   // less than
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后我们在制定好规则之后，通过&lt;code&gt;make_token()&lt;/code&gt;来识别并记录token。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// nemu\src\monitor\sdb\expr.c
static bool make_token(char *e) {
  int position = 0;
  int i;
  regmatch_t pmatch;
  nr_token = 0;
  while (e[position] != &apos;\0&apos;) {
    for (i = 0; i &amp;lt; NR_REGEX; i ++) {
      if (regexec(&amp;amp;re[i], e + position, 1, &amp;amp;pmatch, 0) == 0 &amp;amp;&amp;amp; pmatch.rm_so == 0) {
        char *substr_start = e + position;
        int substr_len = pmatch.rm_eo;
        position += substr_len;

        if (substr_len &amp;gt; 32) return false;
        if (nr_token &amp;gt;= NR_TOKENS) return false;

        switch (rules[i].token_type) {
          case TK_NOTYPE: break;
          case ... :
            tokens[nr_token].type = rules[i].token_type;
            strncpy(tokens[nr_token].str, substr_start, substr_len);
            tokens[nr_token].priority = rules[i].priority;
            nr_token++;
            break;
          default: break;
        }
        break;
      }
    }
    if (i == NR_REGEX) return false;
  }
  return true;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;算术表达式的递归求值&lt;/h2&gt;
&lt;p&gt;得到对应的tokens数组之后，我们就可以根据它们来进行递归求值，整体逻辑如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// nemu\src\monitor\sdb\expr.c
word_t eval(int left, int right, bool *success) {
  if (left &amp;gt; right) /* bad expression */
  else if (left == right) /* return value */
  else if (check_parentheses(left, right) == true) return eval(left+1, right-1, success);
  else {
    /* find dominate operator */
    word_t val1 = eval(left, op-1, success);
    word_t val2 = eval(op+1, right, success);
    switch(op_type) {
      case ... : /* perform calculations */
      default: /* bad expression */
    }
  }
  return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里有一些子函数需要进行编写。首先是判断两边括号是否能够匹配，如果匹配就计算&lt;code&gt;eval(left+1, right-1, success)&lt;/code&gt;，否则进行后续常规计算。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// nemu\src\monitor\sdb\expr.c
bool check_parentheses(int left, int right) {
  if (tokens[left].type != &apos;(&apos; || tokens[right].type != &apos;)&apos;) return false;
  int layer = 0;
  int i;
  for (i = left; i &amp;lt; right; i++) {
    if (tokens[i].type == &apos;(&apos;) layer++;
    else if (tokens[i].type == &apos;)&apos;) layer--;
    if (layer &amp;lt;= 0) return false;
  }
  return (layer == 1);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;另外一个是需要找到计算式中的主运算符。这里需要注意几点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不同类型的运算符的结合方向是不同的。例如加号&lt;code&gt;+&lt;/code&gt;的运算方向是从左到右，而逻辑非&lt;code&gt;!&lt;/code&gt;的运算方向是从右到左。&lt;/li&gt;
&lt;li&gt;括号内的运算符先排除在外，暂时不能作为主运算符，例如&lt;code&gt;1+(2*3)&lt;/code&gt;和&lt;code&gt;(1+2)*3&lt;/code&gt;的主运算符是不同的。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此我们可以编写如下代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// nemu\src\monitor\sdb\expr.c
int check_priority(int left, int right) {
  int dominate_priority = 0;
  int i;
  int layer = 0;
  for (i = left; i &amp;lt;= right; i++) {
    if (tokens[i].type == &apos;(&apos;) layer++;
    else if (tokens[i].type == &apos;)&apos;) layer--;
    if (layer != 0) continue;
    if (tokens[i].priority &amp;gt; dominate_priority) dominate_priority = tokens[i].priority;
  }
  return dominate_priority;
}

int find_dominate_operator(int left, int right, int pri, bool leftToRight) {
  int i;
  int layer = 0;
  if (leftToRight == false) {
    for (i = left; i &amp;lt;= right; i++) {
      if (tokens[i].type == &apos;(&apos;) layer++;
      else if (tokens[i].type == &apos;)&apos;) layer--;
      if (layer != 0) continue;
      if (tokens[i].priority == pri) return i;
    }
  }
  else {
    for (i = right; i &amp;gt;= left; i--) /* same steps */
  }
  return 0;
}

word_t eval(int left, int right, bool *success) {
  if (left &amp;gt; right) { }
  else if (left == right) { }
  else if (check_parentheses(left, right) == true) { }
  else {
    int dominate_priority = check_priority(left, right);
    bool leftToRight;
    if (dominate_priority == 2 || dominate_priority == 13 || dominate_priority == 14) leftToRight = false;
    else leftToRight = true;
    int op = find_dominate_operator(left, right, dominate_priority, leftToRight);
    int op_type = tokens[op].type;    
    switch(op_type) { /* perform calculations */ }
  }
  return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;具体的代码请移步至&lt;a href=&quot;https://github.com/lllirunze/nju-ics-pa/blob/master/nemu/src/monitor/sdb/expr.c&quot;&gt;代码仓&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;实现带有负数的算术表达式&lt;/h2&gt;
&lt;p&gt;当识别出减号的时候，我们需要判断这个符号是减号还是负号，总共有这几种条件，只要满足一条，就可以是负号。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-&lt;/code&gt;是第一个token&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-&lt;/code&gt;的前一个token不是数字、寄存器或者&lt;code&gt;)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// nemu\src\monitor\sdb\expr.c
case &apos;-&apos;:
  if (nr_token != 0 &amp;amp;&amp;amp; (tokens[nr_token-1].type == TK_DEC || tokens[nr_token-1].type == TK_HEX || tokens[nr_token-1].type == TK_REG || tokens[nr_token-1].type == &apos;)&apos;)) {
    tokens[nr_token].type = &apos;-&apos;;
    tokens[nr_token].priority = 4;
  }
  else {
    tokens[nr_token].type = TK_NEG;
    tokens[nr_token].priority = 2;
  }
  strncpy(tokens[nr_token].str, substr_start, substr_len);
  nr_token++;
  break;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;负号是一个单目运算符，因此我们写下&lt;code&gt;case TK_NEG: return -eval(op+1, right, success);&lt;/code&gt;就可以了。&lt;/p&gt;
&lt;h2&gt;除0的确切行为&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;// nemu\src\monitor\sdb\expr.c
switch(op_type) {
  case &apos;/&apos;:
    val1 = eval(left, op-1, success);
    val2 = eval(op+1, right, success);
    if (val2 == 0) {
      Log(&quot;Warning: The divisor cannot be 0.&quot;);
      *success = false;
      return 0;
    }
    return val1 / val2;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;表达式生成器&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;// nemu\tools\gen-expr\gen-expr.c
static inline void gen(char e) {
  int i = 0;
  while (buf[i] != &apos;\0&apos;) i++;
  buf[i] = e;
  buf[i+1] = &apos;\0&apos;;
  return;
}

static inline void gen_num() {
  uint32_t num = ((uint32_t) rand()) % 100;
  sprintf(buf+strlen(buf), &quot;%d&quot;, num);
  return;
}

static inline void gen_op() {
  switch(rand() % 4) {
    case 0: gen(&apos;+&apos;); break;
    case 1: gen(&apos;-&apos;); break;
    case 2: gen(&apos;*&apos;); break;
    case 3: gen(&apos;/&apos;); break;
    default: break;
  }
}

static void gen_rand_expr() {
  char *s = buf;
  if (strlen(buf) &amp;gt; 0 &amp;amp;&amp;amp; *(buf+strlen(buf)-1) == &apos;/&apos;) s = buf+strlen(buf);
  int n = rand() % 3;
  switch(n) {
    case 0:  gen_num();                                  break;
    case 1:  gen(&apos;(&apos;); gen_rand_expr(); gen(&apos;)&apos;);        break;
    default: gen_rand_expr(); gen_op(); gen_rand_expr(); break;
  }

  // test division 0
  if (s != buf) {
    sprintf(code_buf, code_format, s);
    FILE *fp = fopen(&quot;/tmp/.code.c&quot;, &quot;w&quot;);
    assert(fp != NULL);
    fputs(code_buf, fp);
    fclose(fp);

    int ret = system(&quot;gcc /tmp/.code.c -o /tmp/.expr&quot;);
    if(ret != 0) printf(&quot;ret: %d\n&quot;,ret);
		
    fp = popen(&quot;/tmp/.expr&quot;, &quot;r&quot;);
    int result;
    fscanf(fp, &quot;%d&quot;, &amp;amp;result);
    pclose(fp);

    if(result == 0){
      memset((void*)s, 0, strlen(s) * sizeof(char));
      gen_rand_expr();
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在&lt;code&gt;nemu\tools\gen-expr&lt;/code&gt;下运行&lt;code&gt;make run&lt;/code&gt;，即可进行随机测试。&lt;/p&gt;
&lt;h2&gt;扩展表达式求值的功能&lt;/h2&gt;
&lt;p&gt;该内容已经实现，详见前文。&lt;/p&gt;
&lt;h2&gt;监视点池的管理&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;// nemu\src\monitor\sdb\watchpoint.c
typedef struct watchpoint {
  int NO;
  struct watchpoint *next;
  char expression[1024];
  word_t old_val;
} WP;

static WP *new_wp() {
  if (free_ == NULL) return NULL;
  WP *wp = free_;
  free_ = free_-&amp;gt;next;
  return wp;
}

static void free_wp(WP *wp) {
  wp-&amp;gt;next = free_;
  wp-&amp;gt;old_val = 0;
  memset(wp-&amp;gt;expression, 0, sizeof(wp-&amp;gt;expression));
  free_ = wp;
  return;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;实现监视点&lt;/h2&gt;
&lt;p&gt;我们在&lt;code&gt;nemu/Kconfig&lt;/code&gt;中添加一个开关选项，这样在&lt;code&gt;make menuconfig&lt;/code&gt;时可以选择是否进行difftest。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// nemu\Kconfig
menu &quot;Testing and Debugging&quot;

...

config WATCHPOINT
  bool &quot;Enable watchpoints scanning&quot;
  default n
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在menuconfig中勾选监视点扫描后，我们就可以使用&lt;code&gt;CONFIG_WATCHPOINT&lt;/code&gt;参数扫描观察点了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// nemu\src\cpu\cpu-exec.c
static void trace_and_difftest(Decode *_this, vaddr_t dnpc) {
#ifdef CONFIG_WATCHPOINT
  if (scan_wp(_this-&amp;gt;pc)) { nemu_state.state = NEMU_STOP; }
#endif
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;// nemu\src\monitor\sdb\watchpoint.c
bool scan_wp(vaddr_t pc) {
  bool success;
  WP *cur = head;
  while (cur != NULL) {
    success = true;
    word_t new_val = expr(cur-&amp;gt;expression, &amp;amp;success);
    if (cur-&amp;gt;old_val != new_val) return true;
    cur-&amp;gt;old_val = new_val;
    cur = cur-&amp;gt;next;
  }
  return false;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;// nemu\src\monitor\sdb\watchpoint.c
bool scan_wp(vaddr_t pc) {
  bool success;
  WP *cur = head;
  while (cur != NULL) {
    success = true;
    word_t new_val = expr(cur-&amp;gt;expression, &amp;amp;success);
    if (cur-&amp;gt;old_val != new_val) return true;
    cur-&amp;gt;old_val = new_val;
    cur = cur-&amp;gt;next;
  }
  return false;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;:::note[Reference]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.dii.uchile.cl/~daespino/files/Iso_C_1999_definition.pdf&quot;&gt;C99 standard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.csdn.net/sunshihua12829/article/details/47912123&quot;&gt;C语言运算符优先级表&lt;/a&gt;
:::&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>NJU ICS PA0</title><link>https://lllirunze.cn/posts/nju-ics-pa0/</link><guid isPermaLink="true">https://lllirunze.cn/posts/nju-ics-pa0/</guid><description>南京大学计算机科学与技术系计算机系统基础课程实验-PA0</description><pubDate>Mon, 27 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;我在2020年秋季其实已经写过一个&lt;a href=&quot;https://github.com/superpung/TJU-CourseSharing/tree/main/2440072_%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F%E7%BB%BC%E5%90%88%E5%AE%9E%E8%B7%B5&quot;&gt;天津大学的NEMU实验&lt;/a&gt;，这是一个根据南京大学ICS-PA改编的计算机系统综合实践课程，我们写的是x86版本。但是，因为一些众所周知的原因（Ctrl-C + Ctrl-V），我其实并没有完全理解这个实验的内容（都是抄同学的），而且实验也只是进行到PA3课程就结束了。&lt;/p&gt;
&lt;p&gt;因此我打算重新做一遍完整的NJU-ICS-PA，算是重温一下这个南上加南的实验。实验代码已放到&lt;a href=&quot;https://github.com/lllirunze/nju-ics-pa&quot;&gt;这里&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;lllirunze/nju-ics-pa&quot;}&lt;/p&gt;
&lt;h3&gt;虚拟机安装Ubuntu Linux&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.vmware.com/products/desktop-hypervisor/workstation-and-fusion&quot;&gt;VMware Workstation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ubuntu.com/download/desktop&quot;&gt;Ubuntu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.csdn.net/weixin_41805734/article/details/120698714&quot;&gt;vmware安装ubuntu教程&lt;/a&gt;：还有很多教程，仅供参考&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;ps：vmware的安装网址好像和往年有所不同，大家请自行查找即可&lt;/p&gt;
&lt;h3&gt;在github上添加ssh key&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;ssh-keygen -t rsa -C &quot;lirunze.me@gmail.com&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输出结果之后复制&lt;code&gt;~/.ssh/id_rsa.pub&lt;/code&gt;里的内容之后粘贴到Github就行了。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;make menuconfig&lt;/code&gt;为什么会报错&lt;/h3&gt;
&lt;p&gt;缺少了&lt;code&gt;bison&lt;/code&gt;和&lt;code&gt;flex&lt;/code&gt;库，在终端输入&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install bison
sudo apt-get install flex
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;:::note[Reference]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nju-projectn.github.io/ics-pa-gitbook/ics2024/&quot;&gt;南京大学 计算机科学与技术系 计算机系统基础 课程实验 2024&lt;/a&gt;
:::&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>CSS Introductory Basics</title><link>https://lllirunze.cn/posts/css-guide/</link><guid isPermaLink="true">https://lllirunze.cn/posts/css-guide/</guid><description>Dive into layout, styling and responsive design.</description><pubDate>Sun, 26 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;CSS&lt;/strong&gt;（层叠样式表）用于定义网页的样式和布局。利用 CSS，我们可以为网页上的每个元素指定颜色、字体、大小等，从而实现对网页设计的精确控制。&lt;/p&gt;
&lt;h2&gt;CSS 语法&lt;/h2&gt;
&lt;p&gt;典型的 CSS 规则由选择符、属性和值组成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;selector {
    property1: value1;
    property2: value2;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;一个选择器可以有多个声明。&lt;/li&gt;
&lt;li&gt;每个声明必须以&lt;code&gt;;&lt;/code&gt;结尾。&lt;/li&gt;
&lt;li&gt;所有属性和值都以键值对的形式书写。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;p {
    color: blue；
    font-size: 16px；
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;应用 CSS 的三种方法&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;内联样式： 直接在 HTML 元素中使用。&lt;/li&gt;
&lt;li&gt;内部样式表： 在 HTML &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;中的&lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt;标记内。&lt;/li&gt;
&lt;li&gt;外部样式表： 通过 &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;css/style.css&quot;&amp;gt; 标记链接。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这些样式的优先顺序是 &lt;strong&gt;内联 &amp;gt; 内部 &amp;gt; 外部&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;选择器&lt;/h2&gt;
&lt;p&gt;选择器是 CSS 的重要组成部分，因为它们定义了样式将应用于哪些元素或元素组。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;style&amp;gt;
    h2 {
        color: aqua;
    }
    .highlight {
        background-color: yellow;
    }
    #header {
        font-size: 35px;
    }
    * { /* Universal selector */
        font-family: &quot;KaiTi&quot;;
    }
    .father &amp;gt; .son { /* Child selector */
        color: yellowgreen;
    }
    .father p { /* Descendant selector */
        color: brown;
    }
    h3 + p { /* Adjacent sibling selector */
        background-color: red;
    }
    #element:hover { /* Pseudo-class selector */
        background-color: blueviolet;
    }
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;示例:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;h2&amp;gt;Element Selector&amp;lt;/h2&amp;gt;
&amp;lt;h3 class=&quot;highlight&quot;&amp;gt;Class Selector&amp;lt;/h3&amp;gt;
&amp;lt;h4 id=&quot;header&quot;&amp;gt;ID Selector&amp;lt;/h4&amp;gt;
&amp;lt;div class=&quot;father&quot;&amp;gt;
    &amp;lt;p class=&quot;son&quot;&amp;gt;Child Element Selector Example&amp;lt;/p&amp;gt;
    &amp;lt;div&amp;gt;
        &amp;lt;p class=&quot;grandson&quot;&amp;gt;Descendant Selector Example&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;p&amp;gt;Regular p tag&amp;lt;/p&amp;gt;
&amp;lt;h3&amp;gt;Adjacent Sibling Selector Example&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;Regular p tag&amp;lt;/p&amp;gt;

&amp;lt;h3 id=&quot;element&quot;&amp;gt;Pseudo-class Selector Example&amp;lt;/h3&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;CSS 属性&lt;/h3&gt;
&lt;p&gt;CSS 包含多种属性。您可以在&lt;a href=&quot;https://www.runoob.com/css/css-tutorial.html&quot;&gt;菜鸟教程&lt;/a&gt;上了解更多。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;h1 style=&quot;font: bolder 50px &apos;KaiTi&apos;;&quot;&amp;gt;
    Example of the font shorthand property
&amp;lt;/h1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;盒子模型&lt;/h2&gt;
&lt;p&gt;盒子模型在网页设计中至关重要，它由填充、边框和边距组成。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;padding： 元素内部、内容和边框之间的空间&lt;/li&gt;
&lt;li&gt;border： 环绕填充和内容&lt;/li&gt;
&lt;li&gt;margin： 边框周围的外部空间&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/images/posts/css/image-20250121224448072.png&quot; alt=&quot;box-model&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;style&amp;gt;
    .demo {
        background: aqua;
        width: 300px;
        height: 200px;
        border-style: solid;
        border-width: 10px;
        border-color: blueviolet;
    }
&amp;lt;/style&amp;gt;

&amp;lt;div class=&quot;demo&quot;&amp;gt;Content inside the box&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;浮动&lt;/h2&gt;
&lt;p&gt;浮动允许将元素从正常的文档流中移除，并将其定位到左侧或右侧，让其他内容围绕它们流动。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;selector {
    float: left | right | none;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;定位&lt;/h2&gt;
&lt;p&gt;定位可以控制元素的位置。主要有三种定位方式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;相对定位： 相对于正常位置移动元素。&lt;/li&gt;
&lt;li&gt;绝对定位： 相对于位置最近的祖先移动元素。&lt;/li&gt;
&lt;li&gt;固定定位： 将元素相对于浏览器窗口定位，在滚动时保持固定。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;style&amp;gt;
    .box1 {
        height: 350px;
        background-color: aqua;
    }
    .box-normal {
        width: 100px;
        height: 100px;
        background-color: purple;
    }
    .box-relative {
        position: relative;
        left: 120px;
        top: 40px;
    }
    .box-absolute {
        position: absolute;
        left: 120px;
    }
    .box-fixed {
        position: fixed;
        top: 300px;
        right: 0;
    }
&amp;lt;/style&amp;gt;

&amp;lt;h1&amp;gt;Relative Positioning&amp;lt;/h1&amp;gt;
&amp;lt;div class=&quot;box1&quot;&amp;gt;
    &amp;lt;div class=&quot;box-normal&quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;box-relative&quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;box-normal&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;h1&amp;gt;Absolute Positioning&amp;lt;/h1&amp;gt;
&amp;lt;div class=&quot;box1&quot;&amp;gt;
    &amp;lt;div class=&quot;box-normal&quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;box-absolute&quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;box-normal&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;h1&amp;gt;Fixed Positioning&amp;lt;/h1&amp;gt;
&amp;lt;div class=&quot;box1&quot;&amp;gt;
    &amp;lt;div class=&quot;box-fixed&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;:::note[Reference]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1BT4y1W7Aw&quot;&gt;3小时前端入门教程（HTML+CSS+JS）&lt;/a&gt;
:::&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>HTML Introductory Basics</title><link>https://lllirunze.cn/posts/html-guide/</link><guid isPermaLink="true">https://lllirunze.cn/posts/html-guide/</guid><description>Understand HTML tags, structure and syntax, and master the creation and layout of web content.</description><pubDate>Fri, 24 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;HTML&lt;/strong&gt;（超文本标记语言）是网络开发的基础，它使我们能够在网站上构建内容。本文将介绍一些 HTML 的入门概念，包括结构、标记、属性等。&lt;/p&gt;
&lt;p&gt;如果你有一定的编码基础（如学过 Python 等编程语言），一定能轻松理解。&lt;/p&gt;
&lt;h2&gt;必备工具&lt;/h2&gt;
&lt;p&gt;在使用 HTML 时，拥有合适的工具可以让你的开发过程更加顺利。下面是一些 HTML 开发人员必备的工具和插件（如果我们使用 VSCode）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTML/CSS Support&lt;/li&gt;
&lt;li&gt;Live Server&lt;/li&gt;
&lt;li&gt;Auto Rename Tag&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;HTML文档结构&lt;/h2&gt;
&lt;p&gt;HTML 文档需要遵循特定的结构。下面是一个 HTML 文档的基本示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt; &amp;lt;!-- Declaration to tell the browser this is an HTML document --&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt; &amp;lt;!-- Root element --&amp;gt;
    &amp;lt;head&amp;gt;
        &amp;lt;!-- Contains metadata, links to stylesheets, and JavaScript files --&amp;gt;
        &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
        &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
        &amp;lt;title&amp;gt;My First HTML Page&amp;lt;/title&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;!-- Contains the visible content of the page --&amp;gt;
        &amp;lt;h1&amp;gt;Welcome to My Website&amp;lt;/h1&amp;gt;
        &amp;lt;p&amp;gt;This is my first HTML page.&amp;lt;/p&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/images/posts/html/Snipaste_2025-01-24_22-30-28.png&quot; alt=&quot;visual representation&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;常用文本标记&lt;/h2&gt;
&lt;p&gt;HTML 提供了多种用于格式化和结构化文本的标记。下面是一些常见的文本相关元素：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- Heading --&amp;gt;
&amp;lt;h1&amp;gt;Heading Level 1&amp;lt;/h1&amp;gt;
&amp;lt;h2&amp;gt;Heading Level 2&amp;lt;/h2&amp;gt;
&amp;lt;h3&amp;gt;Heading Level 3&amp;lt;/h3&amp;gt;
&amp;lt;!-- &amp;lt;h4&amp;gt;, &amp;lt;h5&amp;gt;, &amp;lt;h6&amp;gt; work similarly for smaller headings --&amp;gt;

&amp;lt;!-- Paragraphs and Text Style --&amp;gt;
&amp;lt;p&amp;gt;This is a paragraph. &amp;lt;b&amp;gt;Bold text&amp;lt;/b&amp;gt; and &amp;lt;i&amp;gt;italic text&amp;lt;/i&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;You can also use &amp;lt;strong&amp;gt;strong emphasis&amp;lt;/strong&amp;gt; and &amp;lt;u&amp;gt;underlined text&amp;lt;/u&amp;gt;.&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- Unordered List --&amp;gt;
&amp;lt;ul&amp;gt;
    &amp;lt;li&amp;gt;Item 1&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Item 2&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;!-- Ordered List --&amp;gt;
&amp;lt;ol&amp;gt;
    &amp;lt;li&amp;gt;First item&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Second item&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;table&amp;gt;
    &amp;lt;tr&amp;gt; &amp;lt;!-- Table row --&amp;gt;
        &amp;lt;th&amp;gt;Header 1&amp;lt;/th&amp;gt; &amp;lt;!-- Table header --&amp;gt;
        &amp;lt;th&amp;gt;Header 2&amp;lt;/th&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;Data 1&amp;lt;/td&amp;gt; &amp;lt;!-- Table data --&amp;gt;
        &amp;lt;td&amp;gt;Data 2&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;Data 3&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;Data 4&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;HTML属性&lt;/h2&gt;
&lt;p&gt;HTML中的属性定义了元素的属性或行为。它们总是在开头标签中指定，由&lt;code&gt;&amp;lt;name=&quot;value&quot;&amp;gt;&lt;/code&gt;组成。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;class&lt;/strong&gt;： 为元素定义一个或多个类，用于CSS风格设计。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;id&lt;/strong&gt;： 为元素指定一个唯一标识符。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;style&lt;/strong&gt;： 元素的内联样式（不建议使用大型样式）。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;tag attribute_name=&quot;attribute_value&quot;&amp;gt;xxx&amp;lt;/tag&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;block、inline和inline-block&lt;/h2&gt;
&lt;p&gt;block元素通常用于组织和结构页面的主要内容。这些元素通常从新一行开始，占据其父元素的全部宽度。常见的块元素包括 &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; 等。&lt;/p&gt;
&lt;p&gt;inline元素通常用于为文本添加样式或为文本的一部分应用样式。这些元素不另起一行，而是与其他内联元素一起出现。内联元素&lt;strong&gt;只占用其内容所需的宽度&lt;/strong&gt;，不会强制换行。常见的内联元素包括 &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; 等。&lt;/p&gt;
&lt;p&gt;inline-block元素结合了块级元素和内联元素的特点。它允许元素出现在同一行中，还可以设置宽度和高度属性，而内联元素不支持这些属性。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;:::note[Reference]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1BT4y1W7Aw&quot;&gt;3小时前端入门教程（HTML+CSS+JS）&lt;/a&gt;
:::&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Markdown Extended Features</title><link>https://lllirunze.cn/posts/markdown-extended/</link><guid isPermaLink="true">https://lllirunze.cn/posts/markdown-extended/</guid><description>Read more about Markdown features in Fuwari</description><pubDate>Wed, 01 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;GitHub Repository Cards&lt;/h2&gt;
&lt;p&gt;You can add dynamic cards that link to GitHub repositories, on page load, the repository information is pulled from the GitHub API.&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Fabrizz/MMM-OnSpotify&quot;}&lt;/p&gt;
&lt;p&gt;Create a GitHub repository card with the code &lt;code&gt;::github{repo=&quot;&amp;lt;owner&amp;gt;/&amp;lt;repo&amp;gt;&quot;}&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;::github{repo=&quot;saicaca/fuwari&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Admonitions&lt;/h2&gt;
&lt;p&gt;Following types of admonitions are supported: &lt;code&gt;note&lt;/code&gt; &lt;code&gt;tip&lt;/code&gt; &lt;code&gt;important&lt;/code&gt; &lt;code&gt;warning&lt;/code&gt; &lt;code&gt;caution&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;:::note
Highlights information that users should take into account, even when skimming.
:::&lt;/p&gt;
&lt;p&gt;:::tip
Optional information to help a user be more successful.
:::&lt;/p&gt;
&lt;p&gt;:::important
Crucial information necessary for users to succeed.
:::&lt;/p&gt;
&lt;p&gt;:::warning
Critical content demanding immediate user attention due to potential risks.
:::&lt;/p&gt;
&lt;p&gt;:::caution
Negative potential consequences of an action.
:::&lt;/p&gt;
&lt;h3&gt;Basic Syntax&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;:::note
Highlights information that users should take into account, even when skimming.
:::

:::tip
Optional information to help a user be more successful.
:::
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Custom Titles&lt;/h3&gt;
&lt;p&gt;The title of the admonition can be customized.&lt;/p&gt;
&lt;p&gt;:::note[MY CUSTOM TITLE]
This is a note with a custom title.
:::&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:::note[MY CUSTOM TITLE]
This is a note with a custom title.
:::
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;GitHub Syntax&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;[!TIP]
&lt;a href=&quot;https://github.com/orgs/community/discussions/16925&quot;&gt;The GitHub syntax&lt;/a&gt; is also supported.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; [!NOTE]
&amp;gt; The GitHub syntax is also supported.

&amp;gt; [!TIP]
&amp;gt; The GitHub syntax is also supported.
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Simple Guides for Fuwari</title><link>https://lllirunze.cn/posts/guide/</link><guid isPermaLink="true">https://lllirunze.cn/posts/guide/</guid><description>How to use this blog template.</description><pubDate>Mon, 01 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Cover image source: &lt;a href=&quot;https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/208fc754-890d-4adb-9753-2c963332675d/width=2048/01651-1456859105-(colour_1.5),girl,_Blue,yellow,green,cyan,purple,red,pink,_best,8k,UHD,masterpiece,male%20focus,%201boy,gloves,%20ponytail,%20long%20hair,.jpeg&quot;&gt;Source&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This blog template is built with &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt;. For the things that are not mentioned in this guide, you may find the answers in the &lt;a href=&quot;https://docs.astro.build/&quot;&gt;Astro Docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Front-matter of Posts&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;---
title: My First Blog Post
published: 2023-09-09
description: This is the first post of my new Astro blog.
image: ./cover.jpg
tags: [Foo, Bar]
category: Front-end
draft: false
---
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attribute&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;title&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The title of the post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;published&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The date the post was published.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A short description of the post. Displayed on index page.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The cover image path of the post.&amp;lt;br/&amp;gt;1. Start with &lt;code&gt;http://&lt;/code&gt; or &lt;code&gt;https://&lt;/code&gt;: Use web image&amp;lt;br/&amp;gt;2. Start with &lt;code&gt;/&lt;/code&gt;: For image in &lt;code&gt;public&lt;/code&gt; dir&amp;lt;br/&amp;gt;3. With none of the prefixes: Relative to the markdown file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tags&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The tags of the post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;category&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The category of the post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;draft&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;If this post is still a draft, which won&apos;t be displayed.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Where to Place the Post Files&lt;/h2&gt;
&lt;p&gt;Your post files should be placed in &lt;code&gt;src/content/posts/&lt;/code&gt; directory. You can also create sub-directories to better organize your posts and assets.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;src/content/posts/
├── post-1.md
└── post-2/
    ├── cover.png
    └── index.md
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Markdown Example</title><link>https://lllirunze.cn/posts/markdown/</link><guid isPermaLink="true">https://lllirunze.cn/posts/markdown/</guid><description>A simple example of a Markdown blog post.</description><pubDate>Sun, 01 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;An h1 header&lt;/h1&gt;
&lt;p&gt;Paragraphs are separated by a blank line.&lt;/p&gt;
&lt;p&gt;2nd paragraph. &lt;em&gt;Italic&lt;/em&gt;, &lt;strong&gt;bold&lt;/strong&gt;, and &lt;code&gt;monospace&lt;/code&gt;. Itemized lists
look like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;this one&lt;/li&gt;
&lt;li&gt;that one&lt;/li&gt;
&lt;li&gt;the other one&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that --- not considering the asterisk --- the actual text
content starts at 4-columns in.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Block quotes are
written like so.&lt;/p&gt;
&lt;p&gt;They can span multiple paragraphs,
if you like.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Use 3 dashes for an em-dash. Use 2 dashes for ranges (ex., &quot;it&apos;s all
in chapters 12--14&quot;). Three dots ... will be converted to an ellipsis.
Unicode is supported. ☺&lt;/p&gt;
&lt;h2&gt;An h2 header&lt;/h2&gt;
&lt;p&gt;Here&apos;s a numbered list:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;first item&lt;/li&gt;
&lt;li&gt;second item&lt;/li&gt;
&lt;li&gt;third item&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note again how the actual text starts at 4 columns in (4 characters
from the left side). Here&apos;s a code sample:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Let me re-iterate ...
for i in 1 .. 10 { do-something(i) }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you probably guessed, indented 4 spaces. By the way, instead of
indenting the block, you can use delimited blocks, if you like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;define foobar() {
    print &quot;Welcome to flavor country!&quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(which makes copying &amp;amp; pasting easier). You can optionally mark the
delimited block for Pandoc to syntax highlight it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import time
# Quick, count to ten!
for i in range(10):
    # (but not *too* quick)
    time.sleep(0.5)
    print i
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;An h3 header&lt;/h3&gt;
&lt;p&gt;Now a nested list:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First, get these ingredients:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;carrots&lt;/li&gt;
&lt;li&gt;celery&lt;/li&gt;
&lt;li&gt;lentils&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Boil some water.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dump everything in the pot and follow
this algorithm:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; find wooden spoon
 uncover pot
 stir
 cover pot
 balance wooden spoon precariously on pot handle
 wait 10 minutes
 goto first step (or shut off burner when done)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do not bump wooden spoon or it will fall.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Notice again how text always lines up on 4-space indents (including
that last line which continues item 3 above).&lt;/p&gt;
&lt;p&gt;Here&apos;s a link to &lt;a href=&quot;http://foo.bar&quot;&gt;a website&lt;/a&gt;, to a &lt;a href=&quot;local-doc.html&quot;&gt;local
doc&lt;/a&gt;, and to a &lt;a href=&quot;#an-h2-header&quot;&gt;section heading in the current
doc&lt;/a&gt;. Here&apos;s a footnote [^1].&lt;/p&gt;
&lt;p&gt;[^1]: Footnote text goes here.&lt;/p&gt;
&lt;p&gt;Tables can look like this:&lt;/p&gt;
&lt;p&gt;size material color&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;9 leather brown
10 hemp canvas natural
11 glass transparent&lt;/p&gt;
&lt;p&gt;Table: Shoes, their sizes, and what they&apos;re made of&lt;/p&gt;
&lt;p&gt;(The above is the caption for the table.) Pandoc also supports
multi-line tables:&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;keyword text&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;red Sunsets, apples, and
other red or reddish
things.&lt;/p&gt;
&lt;p&gt;green Leaves, grass, frogs
and other things it&apos;s
not easy being.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;A horizontal rule follows.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Here&apos;s a definition list:&lt;/p&gt;
&lt;p&gt;apples
: Good for making applesauce.
oranges
: Citrus!
tomatoes
: There&apos;s no &quot;e&quot; in tomatoe.&lt;/p&gt;
&lt;p&gt;Again, text is indented 4 spaces. (Put a blank line between each
term/definition pair to spread things out more.)&lt;/p&gt;
&lt;p&gt;Here&apos;s a &quot;line block&quot;:&lt;/p&gt;
&lt;p&gt;| Line one
| Line too
| Line tree&lt;/p&gt;
&lt;p&gt;and images can be specified like so:&lt;/p&gt;
&lt;p&gt;Inline math equations go in like so: $\omega = d\phi / dt$. Display
math should get its own line and be put in in double-dollarsigns:&lt;/p&gt;
&lt;p&gt;$$I = \int \rho R^{2} dV$$&lt;/p&gt;
&lt;p&gt;$$
\begin{equation*}
\pi
=3.1415926535
;8979323846;2643383279;5028841971;6939937510;5820974944
;5923078164;0628620899;8628034825;3421170679;\ldots
\end{equation*}
$$&lt;/p&gt;
&lt;p&gt;And note that you can backslash-escape any punctuation characters
which you wish to be displayed literally, ex.: `foo`, *bar*, etc.&lt;/p&gt;
</content:encoded></item><item><title>Include Video in the Posts</title><link>https://lllirunze.cn/posts/video/</link><guid isPermaLink="true">https://lllirunze.cn/posts/video/</guid><description>This post demonstrates how to include embedded video in a blog post.</description><pubDate>Tue, 01 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Just copy the embed code from YouTube or other platforms, and paste it in the markdown file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
title: Include Video in the Post
published: 2023-10-19
// ...
---

&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;https://www.youtube.com/embed/5gIf0_xpFPI?si=N1WTorLKL0uwLsU_&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;YouTube&lt;/h2&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;https://www.youtube.com/embed/5gIf0_xpFPI?si=N1WTorLKL0uwLsU_&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;h2&gt;Bilibili&lt;/h2&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1fK4y1s7Qf&amp;amp;p=1&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded></item></channel></rss>