--- title: "03-基本语法要点" aliases: - "基本语法要点" created: 2025-12-23 --- # 基本语法要点 --- ## 一、注释 ### **1.1 三种注释形式** ```java // ═══════════════════════════════════════════════════════════════════════ // 1. 单行注释:用于解释单行代码逻辑 // ═══════════════════════════════════════════════════════════════════════ int count = 0; // 计数器初始化为0 // ═══════════════════════════════════════════════════════════════════════ // 2. 多行注释:用于解释代码块(实际开发中较少使用) // ═══════════════════════════════════════════════════════════════════════ /* * 这是一个多行注释 * 可以跨越多行 * 通常用于临时屏蔽代码块 */ /* 也可以写成一行 */ // ═══════════════════════════════════════════════════════════════════════ // 3. 文档注释:用于生成 JavaDoc API 文档 // ═══════════════════════════════════════════════════════════════════════ /** * 计算两个整数的和 * * @author 张三 * @version 1.0 * @since JDK 1.8 * @param a 第一个加数 * @param b 第二个加数 * @return 两数之和 * @throws ArithmeticException 如果结果溢出 * @see Math#addExact(int, int) */ public int add(int a, int b) { return a + b; } ``` ### **1.2 常用 JavaDoc 标签** ```drawio ``` ``` # 生成 JavaDoc 文档 javadoc -d docs -encoding UTF-8 -charset UTF-8 *.java # 生成的文档结构 docs/ ├── index.html # 首页 ├── allclasses.html # 所有类列表 ├── package-summary.html └── com/ └── example/ └── MyClass.html ``` ### **1.3 注释的本质** ```drawio ``` ### **1.4 注释最佳实践** ```java // ════════════════════════════════════════════════════════════════════════ // ❌ 不好的写法:注释说明显而易见的事情 // ════════════════════════════════════════════════════════════════════════ // 设置 age 为 25 int age = 25; // 如果 age 大于 18 if (age > 18) { // 打印成年 System.out.println("成年"); } // ════════════════════════════════════════════════════════════════════════ // ❌ 不好的写法:注释解释复杂逻辑 // ════════════════════════════════════════════════════════════════════════ // 检查员工是否有资格获得全部福利 // 条件:按小时计费 且 年龄大于65岁 if ((employee.flags & HOURLY_FLAG) && (employee.age > 65)) { // ... } // ════════════════════════════════════════════════════════════════════════ // ✅ 好的写法:用清晰的命名代替注释 // ════════════════════════════════════════════════════════════════════════ if (employee.isEligibleForFullBenefits()) { // ... } // ════════════════════════════════════════════════════════════════════════ // ✅ 好的写法:注释解释 "为什么" 而非 "是什么" // ════════════════════════════════════════════════════════════════════════ // 使用 insertion sort 而非 quicksort,因为数据量小于 10 且几乎有序 // 参考性能测试结果:benchmark_2024.md Arrays.sort(smallArray); // 保留 2 的缓冲空间,避免频繁扩容 // 根据历史数据,99% 的请求不超过 capacity + 2 List items = new ArrayList<>(capacity + 2); ``` ```drawio ``` --- ## 二、标识符与关键字 ### **2.1 标识符** ```drawio ``` **标识符命名规则**: ```drawio ``` **命名规范(约定俗成)**: ```java // ═══════════════════════════════════════════════════════════════════════ // 类名、接口名:大驼峰 (UpperCamelCase) // ═══════════════════════════════════════════════════════════════════════ public class UserService { } public interface OrderRepository { } public class IOException extends Exception { } // ═══════════════════════════════════════════════════════════════════════ // 方法名、变量名:小驼峰 (lowerCamelCase) // ═══════════════════════════════════════════════════════════════════════ public void getUserById() { } int itemCount = 0; String firstName = "John"; // ═══════════════════════════════════════════════════════════════════════ // 常量名:全大写 + 下划线分隔 (SCREAMING_SNAKE_CASE) // ═══════════════════════════════════════════════════════════════════════ public static final int MAX_RETRY_COUNT = 3; public static final String DEFAULT_CHARSET = "UTF-8"; public static final double PI = 3.14159265358979; // ═══════════════════════════════════════════════════════════════════════ // 包名:全小写,用点分隔 // ═══════════════════════════════════════════════════════════════════════ package com.example.project.module; package org.apache.commons.lang3; // ═══════════════════════════════════════════════════════════════════════ // 泛型类型参数:单个大写字母 // ═══════════════════════════════════════════════════════════════════════ public class Box { } // T - Type public class Map { } // K - Key, V - Value public class List { } // E - Element public R execute(Supplier supplier) // R - Return ``` ### **2.2 关键字** ```drawio ``` **Java 关键字分类一览**: ```drawio ``` **关键字详细说明**: ```java // ═══════════════════════════════════════════════════════════════════════ // 访问控制关键字 // ═══════════════════════════════════════════════════════════════════════ public class AccessDemo { public int publicVar; // 公开:任何地方都可访问 protected int protectedVar; // 受保护:同包 + 子类可访问 int defaultVar; // 默认:同包可访问 (无关键字) private int privateVar; // 私有:仅本类可访问 } // ═══════════════════════════════════════════════════════════════════════ // 类相关关键字 // ═══════════════════════════════════════════════════════════════════════ abstract class Animal { } // abstract: 抽象类/方法 class Dog extends Animal { } // extends: 继承 interface Runnable { } // interface: 接口 class Cat implements Runnable { } // implements: 实现接口 final class String { } // final: 不可继承/修改 static int count; // static: 静态成员 // ═══════════════════════════════════════════════════════════════════════ // 特殊关键字 // ═══════════════════════════════════════════════════════════════════════ // native: 本地方法,由 C/C++ 实现 public native int hashCode(); // strictfp: 严格浮点计算,保证跨平台结果一致 strictfp class StrictMath { } // transient: 序列化时忽略该字段 transient int tempData; // volatile: 保证多线程可见性 volatile boolean flag; // synchronized: 同步锁 synchronized void method() { } // assert: 断言(调试用) assert x > 0 : "x must be positive"; // enum: 枚举类型 (JDK 5+) enum Color { RED, GREEN, BLUE } ``` ### **2.3 保留字** ```drawio ``` ### **2.4 字面量 vs 关键字** ```drawio ``` --- ## 三、运算符 ### **3.1 运算符分类概览** ```drawio ``` ### **3.2 自增自减运算符** ```drawio ``` ``` // ═══════════════════════════════════════════════════════════════════════ // 基本用法 // ═══════════════════════════════════════════════════════════════════════ int x = 5; int a = x++; // a = 5, x = 6 (先赋值给a,再自增) int b = ++x; // b = 7, x = 7 (先自增,再赋值给b) System.out.println("a = " + a); // 5 System.out.println("b = " + b); // 7 System.out.println("x = " + x); // 7 // ═══════════════════════════════════════════════════════════════════════ // 图解执行过程 // ═══════════════════════════════════════════════════════════════════════ /* * int x = 5; * int a = x++; * * 执行过程: * ┌─────┐ ┌─────┐ ┌─────┐ * │ x=5 │ ──▶ │ a=5 │ ──▶ │ x=6 │ * └─────┘ 先取值 └─────┘ 后自增 └─────┘ * * * int b = ++x; * * 执行过程: * ┌─────┐ ┌─────┐ ┌─────┐ * │ x=6 │ ──▶ │ x=7 │ ──▶ │ b=7 │ * └─────┘ 先自增 └─────┘ 后取值 └─────┘ */ ``` **经典面试题**: ``` // ═══════════════════════════════════════════════════════════════════════ // 面试题:计算 y 的值 // ═══════════════════════════════════════════════════════════════════════ int x = 5; int y = x++ + ++x + x--; // 详细执行过程分析: ``` ```drawio ``` ```java // 验证代码 public class IncrementDemo { public static void main(String[] args) { int x = 5; int y = x++ + ++x + x--; System.out.println("y = " + y); // 19 System.out.println("x = " + x); // 6 } } ``` **字节码层面分析**: ``` // 源代码 int i = 1; i = i++; // 很多人认为结果是 2,但实际结果是 1! ``` ```drawio ``` ### **3.3 移位运算符** ```drawio ``` **左移运算 <**<: ```drawio ``` **带符号右移 >>**: ```drawio ``` **无符号右移 >**>>: ```drawio ``` ```java // 移位运算验证代码 public class ShiftDemo { public static void main(String[] args) { // 左移 System.out.println("5 << 2 = " + (5 << 2)); // 20 System.out.println("1 << 3 = " + (1 << 3)); // 8 // 带符号右移 System.out.println("20 >> 2 = " + (20 >> 2)); // 5 System.out.println("-8 >> 2 = " + (-8 >> 2)); // -2 // 无符号右移 System.out.println("-8 >>> 2 = " + (-8 >>> 2)); // 1073741822 // 位数超出类型范围时取模 System.out.println("1 << 32 = " + (1 << 32)); // 1 (32 % 32 = 0) System.out.println("1 << 33 = " + (1 << 33)); // 2 (33 % 32 = 1) } } ``` **源码中的移位运算应用**: ```java // ═══════════════════════════════════════════════════════════════════════ // HashMap 源码:计算哈希值 // ═══════════════════════════════════════════════════════════════════════ static final int hash(Object key) { int h; // 将 hashCode 的高 16 位与低 16 位异或 // 目的:让高位也参与索引计算,减少哈希冲突 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } /* * 图解 hash 函数: * * 假设 hashCode = 0b 1010 1010 1010 1010 | 1100 1100 1100 1100 * ─────────高16位────── ─────────低16位────── * * h >>> 16: 0b 0000 0000 0000 0000 | 1010 1010 1010 1010 * * h ^ (h>>>16): 0b 1010 1010 1010 1010 | 0110 0110 0110 0110 * ↑ 高低位信息混合 */ // ═══════════════════════════════════════════════════════════════════════ // HashMap 源码:计算数组容量(取大于等于 cap 的最小 2 的幂) // ═══════════════════════════════════════════════════════════════════════ static final int tableSizeFor(int cap) { int n = cap - 1; n |= n >>> 1; // 将最高位的 1 右移,与原值或运算 n |= n >>> 2; // 继续扩展 n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; } /* * 图解(假设 cap = 10): * * n = 10 - 1 = 9 = 0b 0000 1001 * n >>> 1 = 0b 0000 0100 * n |= n >>> 1 = 0b 0000 1101 * n >>> 2 = 0b 0000 0011 * n |= n >>> 2 = 0b 0000 1111 * ... * 最终 n = 15, n + 1 = 16 (2⁴) */ // ═══════════════════════════════════════════════════════════════════════ // 快速乘除 2 的幂次 // ═══════════════════════════════════════════════════════════════════════ int x = 10; int multiply8 = x << 3; // x * 8, 比 x * 8 更快 int divide4 = x >> 2; // x / 4, 比 x / 4 更快 // ═══════════════════════════════════════════════════════════════════════ // 权限控制(位标志) // ═══════════════════════════════════════════════════════════════════════ public class Permission { public static final int READ = 1 << 0; // 0001 = 1 public static final int WRITE = 1 << 1; // 0010 = 2 public static final int EXECUTE = 1 << 2; // 0100 = 4 public static final int DELETE = 1 << 3; // 1000 = 8 private int permissions = 0; // 添加权限 public void addPermission(int permission) { permissions |= permission; // 0101 | 0010 = 0111 } // 移除权限 public void removePermission(int permission) { permissions &= ~permission; // 0111 & 1101 = 0101 } // 检查权限 public boolean hasPermission(int permission) { return (permissions & permission) == permission; } public static void main(String[] args) { Permission p = new Permission(); p.addPermission(READ | WRITE); // 授予读写权限 System.out.println(p.hasPermission(READ)); // true System.out.println(p.hasPermission(DELETE)); // false } } ``` **移位运算注意事项**: ```drawio ``` --- ## 四、流程控制 ### **4.1 流程控制分类** ```drawio ``` ### **4.2 continue、break、return 对比** ```drawio ``` **图解执行流程**: ```drawio ``` **代码示例**: ```java public class FlowControlDemo { public static void main(String[] args) { // ═══════════════════════════════════════════════════════════════ // continue 示例:跳过偶数 // ═══════════════════════════════════════════════════════════════ System.out.println("=== continue 示例 ==="); for (int i = 0; i < 10; i++) { if (i % 2 == 0) { continue; // 跳过偶数 } System.out.print(i + " "); // 输出: 1 3 5 7 9 } System.out.println(); // ═══════════════════════════════════════════════════════════════ // break 示例:找到目标后退出 // ═══════════════════════════════════════════════════════════════ System.out.println("=== break 示例 ==="); int[] nums = {1, 3, 5, 7, 9, 2, 4}; int target = 7; int index = -1; for (int i = 0; i < nums.length; i++) { if (nums[i] == target) { index = i; break; // 找到后立即退出,不继续遍历 } } System.out.println("找到 " + target + " 在索引 " + index); // ═══════════════════════════════════════════════════════════════ // return 示例:条件满足时提前返回 // ═══════════════════════════════════════════════════════════════ System.out.println("=== return 示例 ==="); printPositive(-5); // 输出: 数字必须为正数 printPositive(10); // 输出: 正数: 10 } public static void printPositive(int num) { if (num <= 0) { System.out.println("数字必须为正数"); return; // 提前返回,后面的代码不执行 } System.out.println("正数: " + num); } } ``` ### **4.3 带标签的 break 和 continue** ```java // ═══════════════════════════════════════════════════════════════════════ // 问题:如何在嵌套循环中跳出外层循环? // ═══════════════════════════════════════════════════════════════════════ // ❌ 普通 break 只能跳出内层循环 for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (i == 1 && j == 1) { break; // 只跳出内层 for } System.out.println("i=" + i + ", j=" + j); } } // 外层循环还会继续执行 i=2 的情况 // ═══════════════════════════════════════════════════════════════════════ // ✅ 使用带标签的 break // ═══════════════════════════════════════════════════════════════════════ outer: // 标签 for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (i == 1 && j == 1) { break outer; // 跳出外层循环 } System.out.println("i=" + i + ", j=" + j); } } // 输出: // i=0, j=0 // i=0, j=1 // i=0, j=2 // i=1, j=0 // (遇到 i=1, j=1 时跳出外层循环) // ═══════════════════════════════════════════════════════════════════════ // 带标签的 continue // ═══════════════════════════════════════════════════════════════════════ outer: for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (j == 1) { continue outer; // 跳到外层循环的下一次迭代 } System.out.println("i=" + i + ", j=" + j); } } // 输出: // i=0, j=0 // i=1, j=0 // i=2, j=0 // (每次 j=1 时跳过内层剩余,进入外层下一次) ``` ```drawio ``` ### **4.4 实际应用场景** ```java // ═══════════════════════════════════════════════════════════════════════ // 场景 1:搜索二维数组 // ═══════════════════════════════════════════════════════════════════════ public static int[] findElement(int[][] matrix, int target) { for (int i = 0; i < matrix.length; i++) { for (int j = 0; j < matrix[i].length; j++) { if (matrix[i][j] == target) { return new int[]{i, j}; // return 最简洁 } } } return null; } // ═══════════════════════════════════════════════════════════════════════ // 场景 2:参数校验(卫语句模式) // ═══════════════════════════════════════════════════════════════════════ public void processOrder(Order order) { // 卫语句:尽早 return,减少嵌套 if (order == null) { log.warn("订单为空"); return; } if (order.getItems().isEmpty()) { log.warn("订单项为空"); return; } if (order.getStatus() != OrderStatus.PENDING) { log.warn("订单状态不是待处理"); return; } // 正常业务逻辑(不需要嵌套在多层 if 中) doProcess(order); } // ═══════════════════════════════════════════════════════════════════════ // 场景 3:过滤处理(continue 跳过不符合条件的项) // ═══════════════════════════════════════════════════════════════════════ public void processValidUsers(List users) { for (User user : users) { // 跳过无效用户 if (user == null) continue; if (!user.isActive()) continue; if (user.getAge() < 18) continue; // 处理有效用户 sendNotification(user); } } // ═══════════════════════════════════════════════════════════════════════ // 场景 4:限制循环次数或超时退出(break) // ═══════════════════════════════════════════════════════════════════════ public Data pollWithTimeout(Queue queue, long timeoutMs) { long startTime = System.currentTimeMillis(); while (true) { Data data = queue.poll(); if (data != null) { return data; } // 超时退出 if (System.currentTimeMillis() - startTime > timeoutMs) { break; } Thread.sleep(100); } return null; // 超时返回 null } ``` ### **4.5 switch 语句增强(JDK 12+)** ``` // ═══════════════════════════════════════════════════════════════════════ // 传统 switch(需要 break) // ═══════════════════════════════════════════════════════════════════════ int dayOfWeek = 3; String dayType; switch (dayOfWeek) { case 1: case 2: case 3: case 4: case 5: dayType = "工作日"; break; // 必须 break,否则会穿透 case 6: case 7: dayType = "周末"; break; default: dayType = "未知"; break; } // ═══════════════════════════════════════════════════════════════════════ // 增强 switch(JDK 12+)- 箭头语法,无需 break // ═══════════════════════════════════════════════════════════════════════ String dayType = switch (dayOfWeek) { case 1, 2, 3, 4, 5 -> "工作日"; // 多个值用逗号分隔 case 6, 7 -> "周末"; default -> "未知"; }; // ═══════════════════════════════════════════════════════════════════════ // switch 表达式(JDK 14+)- 使用 yield 返回值 // ═══════════════════════════════════════════════════════════════════════ String description = switch (dayOfWeek) { case 1 -> "Monday"; case 2 -> "Tuesday"; default -> { // 需要多行代码时用代码块 String result = "Day " + dayOfWeek; yield result; // 使用 yield 返回值 } }; // ═══════════════════════════════════════════════════════════════════════ // 模式匹配 switch(JDK 21+) // ═══════════════════════════════════════════════════════════════════════ Object obj = "Hello"; String result = switch (obj) { case Integer i -> "整数: " + i; case String s -> "字符串: " + s; case Long l -> "长整数: " + l; case null -> "空值"; default -> "其他类型"; }; ``` --- ## 五、总结 ```drawio ```