轩辕李的博客 轩辕李的博客
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

轩辕李

勇猛精进,星辰大海
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Java

    • 核心

      • Java8--Lambda 表达式、Stream 和时间 API
      • Java集合
      • Java IO
      • Java 文件操作
      • Java 网络编程
      • Java运行期动态能力
      • Java可插入注解处理器
      • Java基准测试(JMH)
      • Java性能分析(Profiler)
      • Java调试(JDI与JDWP)
      • Java管理与监控(JMX)
      • Java加密体系(JCA)
      • Java服务发现(SPI)
      • Java随机数生成研究
      • Java数据库连接(JDBC)
      • Java历代版本新特性
      • 写好Java Doc
        • 一、Java Doc概述
          • 1. 什么是Java Doc
          • 2. Java Doc的作用和重要性
        • 二、编写Java Doc的基本规范
          • 1. 注释格式
          • 2. 注释标签
          • HTML标签支持
          • 3. 常用的特殊标签
          • @code
          • @value
          • @throws和@exception
          • @link与@linkplain
          • @inheritDoc
          • <pre>标签
        • 三、注释的内容和示例
          • 1. 模块和包注释的内容和示例
          • 2. 类和接口注释的内容和示例
          • 3. 方法注释的内容和示例
          • 4. 字段注释的内容和示例
        • 四、常见的JavaDoc错误和建议
          • 1. 缺少注释
          • 2. 注释不准确或过于冗长
          • 3. 错误的注释标签使用
          • 4. 缺少必要的使用示例
        • 五、工具和插件推荐
          • 1. JavaDoc命令行工具
          • 常用命令示例
          • 常用参数说明
          • 2. IDE集成工具
          • IntelliJ IDEA
          • Eclipse
          • VS Code
          • 3. 构建工具集成
          • Maven集成
          • Gradle集成
          • 自定义Doclet
        • 六、JavaDoc最佳实践
          • 1. 保持注释与代码同步
          • 2. 编写面向用户的注释
          • 3. 避免过度注释
          • 4. 使用一致的风格
          • 5. 关注API的可用性
          • 6. 定期维护文档
        • 七、总结
      • 聊聊classpath及其资源获取
    • 并发

    • 经验

    • JVM

    • 企业应用

  • Spring

  • 其他语言

  • 工具

  • 后端
  • Java
  • 核心
轩辕李
2023-07-23
目录

写好Java Doc

# 一、Java Doc概述

# 1. 什么是Java Doc

JavaDoc是基于注释的文档生成工具。

在Java代码中,通过特定的注释格式,可以标注类、方法、字段等的用途、参数、返回值等相关信息。

JavaDoc工具会解析这些注释,并生成HTML格式的文档,以供开发者阅读和使用。

# 2. Java Doc的作用和重要性

JavaDoc的作用非常重要,它可以帮助开发者更好地理解代码、使用代码和维护代码。

具体来说,JavaDoc的作用包括:

  • 提供代码的详细说明:通过JavaDoc注释,可以清晰地描述类、方法、字段的功能、用途和使用方法,使其他开发者能够更好地理解和使用代码
  • 自动生成API文档:JavaDoc工具可以根据注释生成HTML格式的API文档,提供给其他开发者使用。这样,其他开发者就可以快速了解代码的接口和使用规范
  • 代码可读性增强:良好的JavaDoc注释可以增加代码的可读性,使代码更易于理解和维护。注释可以提供额外的上下文信息,帮助其他开发者快速理解代码的意图和逻辑
  • 代码文档化和规范化:通过编写JavaDoc注释,可以迫使开发者对代码进行更加规范和清晰的书写,提高代码的质量和可维护性

# 二、编写Java Doc的基本规范

在编写JavaDoc时,我们需要遵循一些基本的规范,包括注释格式、注释标签和文档结构等。

这些规范可以帮助我们编写清晰、易读和易于维护的文档。

# 1. 注释格式

JavaDoc注释使用/**开头,以*/结尾,位于需要注释的代码上方。注释可以跨越多行,也可以位于一行内。以下是一个示例:

/**
 * 这是一个示例的JavaDoc注释
 * <p>
 * 这个类用于演示JavaDoc注释的基本格式和用法。
 * 
 * @author 作者名
 * @version 1.0
 * @since 1.0
 */
public class MyClass {
    // ...
}

# 2. 注释标签

JavaDoc注释使用特定的标签来标记不同的注释内容。常用的注释标签包括:

  • @param:用于描述方法的参数,指定参数的名称和说明
  • @return:用于描述方法的返回值,指定返回值的类型和说明
  • @throws:用于描述方法可能抛出的异常,指定异常的类型和说明
  • @see:用于引用其他相关的文档或类
  • @deprecated:用于标记已过时的方法或类
  • @author:用于指定作者姓名
  • @version:用于指定版本信息
  • @since:用于指明最早出现在哪个版本,可填版本号或日期,有时也可表明可运行的JDK版本

以下是一个示例:

/**
 * 获取用户信息
 * <p>
 * 该方法根据提供的用户名和年龄信息,返回格式化的用户信息字符串。
 * 
 * @param name 用户名,不能为{@code null}或空字符串
 * @param age 用户年龄,必须大于等于0
 * @return 格式化的用户信息字符串
 * @throws IllegalArgumentException 如果用户名为空或年龄小于0
 * @see OtherClass
 * @deprecated 请使用{@link #getFormattedUserInfo(String, int)}代替
 * @author John
 * @version 1.0
 * @since 1.0
 */
public String getUserInfo(String name, int age) throws IllegalArgumentException {
    // ...
}

# HTML标签支持

在注释中,你可以使用HTML标签来做一些格式处理。比如:

/**
 * 请参考 <a href="https://example.com">此链接</a> 获取更多信息。
 * <p>
 * 支持的HTML标签包括:
 * <ul>
 *   <li><b>粗体文本</b></li>
 *   <li><i>斜体文本</i></li>
 *   <li><code>代码片段</code></li>
 * </ul>
 */
public void referenceLink() {
    // 方法实现
}

在Java 9之后,JavaDoc开始支持HTML5标签,比如:

/**
 * <section>
 * <h3>使用示例</h3>
 * <p>这是一个详细的使用说明。</p>
 * </section>
 */
public void sectionExample() {
    // 方法实现
}

# 3. 常用的特殊标签

除了基本标签,还有一些特殊的标签用于标记特定的内容:

# @code

将关键字或代码片段格式化为代码样式。以下情况必须使用该标签:

  • Java关键字
  • 包名、类名、方法名、接口名、字段名
  • 参数名
  • 代码示例
// 关键字
{@code true}
{@code null}

// 变量名
{@code CharSequence}

// 代码
{@code int var = 1;}

# @value

用于引用常量的值,只能用于对常量进行注释:

/**
 * 默认的列表分隔符。当前值为:{@value Constant#DEFAULT_LIST_SEPARATOR}
 */
public String getListSeparator() {
    return listSeparator;
}

# @throws和@exception

用于标记方法可能抛出的异常。两者作用相同,推荐使用@throws:

/**
 * 验证用户输入信息
 * 
 * @param name 用户名
 * @param age 用户年龄
 * @throws IllegalArgumentException 如果用户名为{@code null}或空字符串
 * @throws IllegalArgumentException 如果年龄小于0或大于150
 */
public void validateUser(String name, int age) throws IllegalArgumentException {
    // ...
}

# @link与@linkplain

用于引用其他相关的文档或类:

  • @link:直接将超链接地址作为显示文本,格式为{@link 地址}
  • @linkplain:可以自定义显示文本,格式为{@linkplain 地址 显示文本}

格式说明:

  • 完整格式:包名.类名#方法名(参数类型)
  • 当前包内可省略包名
  • 当前类内可省略类名

与@see的区别:

  • @link可以放在注释的任意位置
  • @see必须独立成行,放在注释最开始
/**
 * 字符串处理工具类
 * <p>
 * 完整格式引用:{@link java.lang.String#charAt(int)}
 * 省略包名:{@link String}
 * 当前类方法:{@link #length()}
 * 
 * 此实现继承了{@link com.service.BaseManagerImpl},以复用其中的dao接口。
 * 使用方法与{@linkplain com.common.web.SimpleDBAction SimpleDBAction}基本一致。
 * 
 * @see DoubleStream
 */
public class StringUtils {
    // ...
}

# @inheritDoc

用于继承父类或接口的注释,避免重复编写相同的文档:

/**
 * {@inheritDoc}
 * <p>
 * 此实现添加了额外的验证逻辑。
 */
@Override
public void process(String data) {
    // 实现细节
}

# <pre>标签

用于保持文本的原始格式(包括空格和换行),常用于代码示例:

/**
 * 计算阶乘
 * <p>
 * 使用示例:
 * <pre>
 * public static void main(String[] args) {
 *     System.out.println(factorial(5)); // 输出: 120
 *     System.out.println(factorial(0)); // 输出: 1
 * }
 * </pre>
 * 
 * @param n 非负整数
 * @return n的阶乘
 */
public static int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

# 三、注释的内容和示例

在JavaDoc中,不同的注释类型有不同的内容要求。本章将介绍模块和包注释、类和接口注释、方法注释以及字段注释的内容和示例。

# 1. 模块和包注释的内容和示例

模块和包注释通常用于描述整个代码模块或包的功能、用途和设计思路。其内容通常包括以下几个方面:

  • 模块或包的名称和简要描述
  • 模块或包的设计目标和用途
  • 模块或包的依赖关系和关联的其他模块或包
  • 模块或包的作者和版本信息

以下是一个示例:

/**
 * 字符串处理工具模块
 * <p>
 * 提供常用的字符串操作工具方法,包括格式化、验证、转换等功能。
 * 
 * <h3>主要功能:</h3>
 * <ul>
 *   <li>字符串拼接和分割</li>
 *   <li>字符串格式化和解析</li>
 *   <li>字符串验证和清理</li>
 *   <li>编码转换</li>
 * </ul>
 * 
 * @author John
 * @version 1.0
 * @since 1.0
 */
module stringutils {
    exports com.example.stringutils;
    requires java.base;
}

# 2. 类和接口注释的内容和示例

类和接口注释用于描述类或接口的功能、用途和设计思路。其内容通常包括以下几个方面:

  • 类或接口的名称和简要描述
  • 类或接口的设计目标和用途
  • 类或接口的构造方法和方法的功能和用途
  • 类或接口的作者和版本信息

以下是一个示例:

/**
 * 图形抽象类
 * <p>
 * 定义了所有图形的基本属性和行为,包括面积计算、周长计算等通用方法。
 * 子类需要实现具体的计算逻辑。
 * 
 * <h3>主要功能:</h3>
 * <ul>
 *   <li>提供面积和周长的抽象计算方法</li>
 *   <li>图形信息的格式化输出</li>
 *   <li>图形类型的标识和比较</li>
 * </ul>
 * 
 * <h3>使用示例:</h3>
 * <pre>
 * Shape circle = new Circle(5.0);
 * double area = circle.getArea();
 * System.out.println("面积: " + area);
 * </pre>
 * 
 * @author John
 * @version 1.0
 * @since 1.0
 * @see Circle
 * @see Rectangle
 */
public abstract class Shape {
    // ...
}

# 3. 方法注释的内容和示例

方法注释用于描述方法的功能、参数、返回值和异常等信息。其内容通常包括以下几个方面:

  • 方法的功能和用途
  • 方法的参数及其说明
  • 方法的返回值及其说明
  • 方法可能抛出的异常及其说明
  • 方法的作者和版本信息

以下是一个示例:

/**
 * 执行两个整数的除法运算
 * <p>
 * 该方法执行 a÷b 的除法运算,并返回整数结果。当除数为0时会抛出异常。
 * 
 * <h3>注意事项:</h3>
 * <ul>
 *   <li>除数不能为0</li>
 *   <li>结果向下取整</li>
 *   <li>支持负数运算</li>
 * </ul>
 * 
 * @param dividend 被除数
 * @param divisor 除数,不能为{@code 0}
 * @return 除法运算的整数结果
 * @throws IllegalArgumentException 如果除数为{@code 0}
 * @throws ArithmeticException 如果发生溢出
 * @since 1.0
 * @see Math#divideExact(int, int)
 */
public int divide(int dividend, int divisor) throws IllegalArgumentException, ArithmeticException {
    if (divisor == 0) {
        throw new IllegalArgumentException("除数不能为0");
    }
    return dividend / divisor;
}

# 4. 字段注释的内容和示例

字段注释用于描述类的字段的用途和意义。

以下是一个示例:

/**
 * 用户姓名
 * <p>
 * 存储用户的完整姓名,不能为{@code null}或空字符串。
 * 长度限制为1-50个字符。
 * 
 * @since 1.0
 */
private String name;

/**
 * 最大重试次数
 * <p>
 * 当操作失败时的最大重试次数,默认值为{@value}。
 */
public static final int MAX_RETRY_COUNT = 3;

/**
 * 用户状态枚举
 * <p>
 * 表示用户的当前状态,可能的值包括:
 * <ul>
 *   <li>{@link UserStatus#ACTIVE} - 活跃状态</li>
 *   <li>{@link UserStatus#INACTIVE} - 非活跃状态</li>
 *   <li>{@link UserStatus#SUSPENDED} - 暂停状态</li>
 * </ul>
 */
private UserStatus status;

# 四、常见的JavaDoc错误和建议

在编写JavaDoc时,可能会出现一些常见的错误。本章将介绍一些常见的JavaDoc错误,并提供一些建议来避免这些错误。

# 1. 缺少注释

问题:没有或者缺少注释会导致其他开发者难以理解代码的意图和功能。

建议:

  • 所有公共API(类、方法、字段)都应该有JavaDoc注释
  • 及时添加注释,不要留到最后统一补充
  • 确保注释清晰、准确地描述代码的功能和用途

# 2. 注释不准确或过于冗长

问题:注释与实际代码不符,或者注释过于冗长影响阅读。

建议:

  • 注释应该简洁明了,重点描述"做什么"而不是"怎么做"
  • 避免重复代码中已经很明显的信息
  • 当代码修改时,同步更新注释
// ❌ 冗长且无意义的注释
/**
 * 这个方法接收一个整数参数n,然后计算n的阶乘,
 * 阶乘就是从1乘到n的结果,比如5的阶乘就是1*2*3*4*5=120
 */
public int factorial(int n) { ... }

// ✅ 简洁明了的注释
/**
 * 计算指定数字的阶乘
 * 
 * @param n 非负整数
 * @return n的阶乘值
 * @throws IllegalArgumentException 如果n为负数
 */
public int factorial(int n) { ... }

# 3. 错误的注释标签使用

问题:不正确的注释标签可能导致生成的文档不符合预期。

常见错误:

  • 所有参数都要有@param标签
  • 有返回值的方法必须有@return标签
  • 声明的异常必须有@throws标签
  • 标签顺序应该规范:描述 → @param → @return → @throws → @see → @since → @author
// ❌ 错误的标签使用
/**
 * 用户登录
 * @return 登录结果
 * @param username 用户名
 * @param password 密码
 */
public boolean login(String username, String password) { ... }

// ✅ 正确的标签使用
/**
 * 用户登录验证
 * 
 * @param username 用户名,不能为{@code null}
 * @param password 密码,不能为{@code null}
 * @return {@code true}如果登录成功,{@code false}如果失败
 * @throws IllegalArgumentException 如果用户名或密码为{@code null}
 */
public boolean login(String username, String password) { ... }

# 4. 缺少必要的使用示例

问题:复杂的API缺少使用示例,用户不知道如何正确使用。

建议:

  • 为复杂的API提供使用示例
  • 使用<pre>标签保持代码格式
  • 示例要完整且可运行
/**
 * 批量处理用户数据
 * <p>
 * 使用示例:
 * <pre>
 * List&lt;User&gt; users = Arrays.asList(
 *     new User("张三", 25),
 *     new User("李四", 30)
 * );
 * 
 * ProcessResult result = processor.batchProcess(users, 
 *     user -&gt; user.getAge() &gt; 18);
 * System.out.println("处理了 " + result.getProcessedCount() + " 个用户");
 * </pre>
 */
public ProcessResult batchProcess(List<User> users, Predicate<User> filter) { ... }

# 五、工具和插件推荐

在编写JavaDoc时,有一些工具和插件可以帮助我们更好地生成和维护文档。本章将介绍一些常用的工具和插件,并提供一些推荐。

# 1. JavaDoc命令行工具

JavaDoc命令行工具是Java官方提供的文档生成工具。它可以通过命令行方式运行,生成HTML格式的文档,并且可以方便地集成到自动化构建工具中。

# 常用命令示例

生成单个类的文档:

javadoc -d docs/ -encoding UTF-8 MyClass1.java MyClass2.java

生成整个项目的文档:

javadoc -d docs/ -sourcepath src/ -subpackages com.example -encoding UTF-8

生成HTML5格式的文档(Java 9+):

javadoc -d docs/ -sourcepath src/ -subpackages com.example -html5 -encoding UTF-8

# 常用参数说明

  • -d:指定输出目录
  • -sourcepath:指定源代码路径
  • -subpackages:递归处理指定包及其子包
  • -encoding:指定源文件编码
  • -html5:生成HTML5格式文档(推荐)
  • -private:包含私有成员
  • -author:包含@author标签信息
  • -version:包含@version标签信息

# 2. IDE集成工具

现代IDE都提供了强大的JavaDoc支持,可以大大提高文档编写效率。

# IntelliJ IDEA

  • 自动生成:输入/**后按回车,自动生成方法参数的@param标签
  • 实时预览:View → Tool Windows → Documentation
  • 快捷键:Ctrl+Q(Windows/Linux)或F1(Mac)快速查看文档
  • 代码检查:实时检测缺失的JavaDoc注释

推荐插件:

  • Easy Javadoc (opens new window):快速生成中文JavaDoc模板
  • JavaDoc Generator (opens new window):批量生成JavaDoc注释

# Eclipse

  • 自动生成:Alt+Shift+J生成JavaDoc模板
  • 预览功能:Window → Show View → Javadoc
  • 导出功能:Project → Generate Javadoc

# VS Code

  • 插件推荐:
    • Java Extension Pack
    • JavaDoc Tools

# 3. 构建工具集成

# Maven集成

Maven Javadoc Plugin配置示例:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-javadoc-plugin</artifactId>
    <version>3.4.1</version>
    <configuration>
        <encoding>UTF-8</encoding>
        <locale>zh_CN</locale>
        <html5>true</html5>
        <doclint>none</doclint>
        <additionalOptions>-Xdoclint:none</additionalOptions>
    </configuration>
    <executions>
        <execution>
            <id>attach-javadocs</id>
            <goals>
                <goal>jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

常用命令:

# 生成JavaDoc文档
mvn javadoc:javadoc

# 打包JavaDoc为jar
mvn javadoc:jar

# Gradle集成

javadoc {
    encoding = 'UTF-8'
    charSet = 'UTF-8'
    author = true
    version = true
    use = true
    windowTitle = "API Documentation"
    docTitle = "API Documentation"
    options.addStringOption('Xdoclint:none', '-quiet')
}

task javadocJar(type: Jar) {
    classifier = 'javadoc'
    from javadoc
}

# 自定义Doclet

对于特殊需求,可以开发自定义的Doclet来生成特定格式的文档:

public class CustomDoclet extends StandardDoclet {
    // 自定义文档生成逻辑
}

# 六、JavaDoc最佳实践

编写JavaDoc注释时,遵循最佳实践可以提高代码的可读性和可维护性。

# 1. 保持注释与代码同步

核心原则:注释与代码必须保持一致。

// ❌ 注释与代码不一致
/**
 * 计算两个数的和
 */
public int multiply(int a, int b) {
    return a * b;
}

// ✅ 注释与代码一致
/**
 * 计算两个数的乘积
 */
public int multiply(int a, int b) {
    return a * b;
}

实践建议:

  • 代码修改时,同步更新注释
  • 在代码审查中检查注释的准确性
  • 使用IDE的JavaDoc检查功能

# 2. 编写面向用户的注释

重点描述:

  • 功能:这个方法/类做什么
  • 用途:什么时候使用
  • 限制:有什么约束条件
  • 副作用:会产生什么影响
/**
 * 线程安全的计数器
 * <p>
 * 提供原子性的递增操作,适用于高并发环境下的计数场景。
 * 内部使用{@link AtomicInteger}实现,保证操作的原子性。
 * 
 * <h3>使用场景:</h3>
 * <ul>
 *   <li>访问统计</li>
 *   <li>ID生成</li>
 *   <li>并发计数</li>
 * </ul>
 * 
 * @author 张三
 * @since 1.0
 */
public class ThreadSafeCounter {
    // ...
}

# 3. 避免过度注释

避免显而易见的注释:

// ❌ 无意义的注释
/**
 * 获取用户名
 * @return 用户名
 */
public String getUserName() {
    return userName;
}

// ✅ 有价值的注释(如果需要注释的话)
/**
 * 获取用户的显示名称
 * <p>
 * 如果用户设置了昵称,返回昵称;否则返回真实姓名。
 * 
 * @return 用户的显示名称,不会为{@code null}
 */
public String getDisplayName() {
    return nickname != null ? nickname : realName;
}

# 4. 使用一致的风格

建立团队规范:

/**
 * [一句话概述]
 * <p>
 * [详细描述,可选]
 * 
 * <h3>[特殊说明标题,可选]</h3>
 * [特殊说明内容]
 * 
 * @param [参数名] [参数描述]
 * @return [返回值描述]
 * @throws [异常类型] [抛出条件]
 * @see [相关引用]
 * @since [版本号]
 * @author [作者]
 */

# 5. 关注API的可用性

为用户着想:

/**
 * JSON序列化工具类
 * <p>
 * 提供对象与JSON字符串之间的转换功能,基于Jackson库实现。
 * 
 * <h3>线程安全性:</h3>
 * 该类是线程安全的,可以在多线程环境中使用。
 * 
 * <h3>性能考虑:</h3>
 * 内部缓存了{@link ObjectMapper}实例,避免重复创建的开销。
 * 
 * <h3>使用示例:</h3>
 * <pre>
 * // 对象转JSON
 * User user = new User("张三", 25);
 * String json = JsonUtils.toJson(user);
 * 
 * // JSON转对象
 * User user = JsonUtils.fromJson(json, User.class);
 * </pre>
 * 
 * @author 李四
 * @since 1.0
 */
public class JsonUtils {
    // ...
}

# 6. 定期维护文档

持续改进:

  • 定期审查JavaDoc文档的质量
  • 收集用户反馈,改进文档内容
  • 随着API演进,及时更新文档
  • 使用文档生成工具检查完整性

# 七、总结

本文全面介绍了JavaDoc注释的编写规范和最佳实践。

核心要点回顾:

  1. 基础规范:掌握JavaDoc的基本格式、常用标签和HTML支持
  2. 注释类型:了解不同代码元素(类、方法、字段)的注释要求
  3. 避免错误:识别常见的JavaDoc错误并采用正确的编写方式
  4. 工具支持:充分利用IDE、构建工具和插件提高效率
  5. 最佳实践:注重注释与代码的同步、面向用户的描述和一致的风格

实践建议:

  • 将JavaDoc编写融入日常开发流程
  • 建立团队的文档规范和检查机制
  • 定期维护和更新API文档
  • 重视文档的用户体验和可读性

通过编写高质量的JavaDoc注释,我们不仅能为其他开发者提供清晰的API说明,还能提高代码的可维护性和团队协作效率。良好的文档是优秀代码的重要组成部分,值得我们投入时间和精力去完善。

祝你变得更强!

编辑 (opens new window)
#JavaDoc
上次更新: 2025/08/16
Java历代版本新特性
聊聊classpath及其资源获取

← Java历代版本新特性 聊聊classpath及其资源获取→

最近更新
01
AI时代的编程心得
09-11
02
Claude Code与Codex的协同工作
09-01
03
Claude Code实战之供应商切换工具
08-18
更多文章>
Theme by Vdoing | Copyright © 2018-2025 京ICP备2021021832号-2 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式