Java 关键字与保留字字典。体例:每条给语义与版本约束、语法与多场景示例、边界与常见坑。Java 共 50 个关键字(含 const/goto 保留字)。
1. abstract – 抽象类与方法
描述
抽象方法只有签名没有实现,抽象类不能实例化。抽象类可以有构造器(供子类调用)、具体方法与字段——它是「半成品类」。抽象方法不能是 static/private/final。
语法和示例
abstract class Shape { // 不能 new Shape()
protected final String name; // 可有字段
Shape(String n) { this.name = n; } // 可有构造器
abstract double area(); // 无方法体
double describe() { // 可有具体方法
return name + ":" + area();
}
}
class Circle extends Shape {
private final double r;
Circle(double r) { super("circle"); this.r = r; }
@Override double area() { return Math.PI * r * r; }
}
// 匿名子类(只重写一两个方法时)
Shape unit = new Shape("unit") {
double area() { return 1.0; }
};注意事项
- 抽象类不能实例化,但可以声明为其类型的引用
- 抽象方法不可 static/private/final——static 无法动态绑定,private 子类看不见,final 不许覆盖
- 子类若不实现全部抽象方法,则子类本身必须也是 abstract
- 抽象类 vs 接口:需要状态(字段)和构造逻辑时用抽象类;只要能力契约用接口
2. assert – 断言
描述
运行时校验内部不变量。默认关闭,需 -ea(enableassertions)开启。语法两种:assert 条件; 与 assert 条件 : 消息;。
语法和示例
// 运行:java -ea Main
int divide(int a, int b) {
assert b != 0 : "除数不能为 0,收到 " + b;
return a / b;
}
// 校验后置条件
int[] sort(int[] in) {
int[] out = in.clone();
java.util.Arrays.sort(out);
assert isSorted(out) : "排序结果未有序";
return out;
}注意事项
- 默认关闭——生产环境一般不开,别用它做业务校验(用户输入校验必须手动抛异常)
- 断言失败抛 AssertionError(Error 子类,不该被 catch Exception 吞掉)
- IDE/构建工具可能默认开启(如 Maven surefire 默认启用断言),但生产 JVM 默认关闭
- 永远不要用它替代参数校验;也不要写有副作用的表达式(关闭时不执行)
3. boolean / byte / short / int / long / float / double / char – 基本类型
描述
8 种基本类型是值语义、非对象、不受 GC 管理。宽度:byte 8、short 16、char 16(无符号)、int 32、long 64、float 32、double 64。boolean 无位宽定义。
语法和示例
int i = 42; // 默认 int
long l = 9_000_000_000L; // 超 int 范围必须 L 后缀;下划线分位(7+)
double d = 3.14159; // 默认 double
float f = 2.5f; // 必须 f 后缀,否则编译错
char c = '中'; // 单引号,可存中文(16 位)
byte b = (byte) 200; // 溢出需显式窄化 → -56
boolean ok = true; // 只有 true/false,与 0/1 不互转
// 字面量形式
int bin = 0b1010; int oct = 017; int hex = 0xFF;
char tab = '\t';注意事项
- char 是 16 位 UTF-16 代码单元,不能直接表示所有 Unicode(emoji 需 surrogate pair,用 String 存)
- float 字面量不加 f 会编译错(2.5 是 double,double→float 需窄化)
- 整型字面量默认 int,超过 2147483647 必须加 L,否则编译错
- 窄化转换(long→int、double→float)必须显式强转,且可能丢精度或截断
- 基本类型数组是连续内存(int[] 1000 个 = 4000 字节),比 Integer[] 省得多
4. break / continue – 跳出与继续
描述
break 终止最近一层循环或 switch;continue 跳过本轮剩余语句进入下一轮。两者都可带标签(label:)跳到指定外层循环。
语法和示例
// 带标签跳出双重循环
outer:
for (int[] row : grid) {
for (int v : row) {
if (v < 0) break outer; // 直接跳出两层
if (v == 0) continue; // 跳过本轮
if (v == 0) continue outer; // 跳到外层下一轮
sum += v;
}
}
// switch 里的 break(传统语法必需)
switch (k) { case 1: doA(); break; default: break; }注意事项
- 标签名后必须紧跟冒号,标签只能标在循环或语句块前
- switch 表达式(14+)的 -> 箭头语法不需要 break(无 fall-through)
- continue 在 switch 内是编译错误(switch 不是循环)
- for-each 里 continue 正常跳过;但想「跳过并移除」需用 Iterator 或 removeIf
5. case / default / switch – 分支
描述
传统 switch 语句有 fall-through(忘 break 会贯穿到下一分支);14+ 的 switch 表达式用 -> 无贯穿、可返回值、编译器检查穷尽性。
语法和示例
// 传统语法:注意 break
switch (day) {
case MON: case TUE: case WED:
System.out.println("工作日"); break; // 漏 break 会贯穿
case SAT: case SUN:
System.out.println("周末"); break;
default:
System.out.println("未知");
}
// switch 表达式(14+,推荐)
String type = switch (day) {
case SAT, SUN -> "周末";
case MON, TUE, WED, THU, FRI -> "工作日";
}; // enum 全覆盖可省 default
// 带代码块与 yield
int len = switch (s) {
case null -> 0;
default -> { log(s); yield s.length(); }
};注意事项
- 传统 switch 的贯穿是有意设计的(case 1: case 2: 共享分支),但绝大多数 bug 来自忘写 break
- switch 表达式必须穷尽:enum 全覆盖可省 default,其他类型必须写 default
- switch 表达式里 case null 需显式写(否则 null 会抛 NPE,21+ 才允许 case null)
- 用途:字符串/枚举分发用 switch;模式匹配(类型分支)用 21+ 的 switch 模式
6. catch / finally / try – 异常处理
描述
catch 按声明顺序匹配类型(子类必须在前);finally 无论正常返回还是抛异常都执行;try-with-resources 自动关闭 AutoCloseable。
语法和示例
// try-with-resources(推荐,自动关闭且异常不互相覆盖)
try (var in = new BufferedReader(new FileReader("a.txt"));
var out = new PrintWriter("b.txt")) {
in.lines().forEach(out::println);
} catch (FileNotFoundException e) { // 子类在前
log("文件不存在", e);
} catch (IOException e) { // 父类在后
throw new UncheckedIOException(e);
} finally {
metrics.increment("io.attempt"); // 无论如何都执行
}
// 多类型捕获(7+)
try { risky(); }
catch (IllegalStateException | IllegalArgumentException e) {
log(e.getMessage()); // e 隐式为 final
}注意事项
- catch 顺序:子类异常必须放前面,否则编译器报错(父类已捕获,子类分支不可达)
- finally 里不要 return/throw——会吞掉 try 里的异常或返回值
- try-with-resources 关闭顺序与声明顺序相反;多个异常时主异常保留,其余进 suppressed
- 不要 catch Throwable/Error(OOM、StackOverflowError 无法安全恢复)
- 返回集合/流时考虑 try-with-resources 管理底层资源,避免调用方遗忘
7. class / interface / enum / record – 类型声明
描述
class 可实例化模板;interface 是能力契约(可有 default/static/private 方法,字段隐式 public static final);enum 实例固定的类(可带构造器与方法);record 不可变数据载体(16+)。
语法和示例
interface Fly {
int MAX = 100; // 隐式 public static final
void takeoff(); // 抽象方法
default void fly() { takeoff(); } // 默认实现(8+)
static Fly simple() { return () -> {}; } // 静态方法
}
enum Level {
LOW(1), MID(5), HIGH(10); // 实例固定
final int weight;
Level(int w) { weight = w; }
int boosted() { return weight * 2; }
}
record Point(int x, int y) { // 自动 equals/hashCode/toString
Point { // 紧凑构造器可校验
if (x < 0) throw new IllegalArgumentException();
}
}
class Bird implements Fly {
public void takeoff() { System.out.println("起飞"); }
}注意事项
- 接口字段隐式 public static final——写 private 字段是编译错误(要状态用抽象类)
- enum 的构造器隐式 private;不能 new Level(),只能通过常量引用
- record 字段隐式 final,不可继承 record(可被 record 实现接口)
- 一个文件只能有一个 public 顶层类型,且文件名必须匹配
- 17+ 可 sealed interface 限定实现者,配合 switch 穷尽检查
8. const / goto – 保留字
描述
两个从未启用的保留字(为兼容 C/C++ 语法预留)。写成标识符会编译错误,但也没有任何功能。
语法和示例
// const int x = 1; // 编译错误:不是有效语法
// goto end; // 同上
// 替代方案:
final int X = 1; // 常量
break outer; // 有限跳转(带标签)注意事项
- Java 用 final 表达常量,没有 const
- Java 不支持 goto(无限制跳转被认为有害),只能用带标签 break/continue 做有限跳转
- 这两个词在 IDE 里仍会被高亮为关键字(保留字),不能作变量名
9. extends / implements – 继承与实现
描述
extends 单继承类(或接口扩展接口可多个);implements 可多实现接口。构造器不被继承,子类必须链式调用父类构造器。
语法和示例
class Base {
Base() { }
Base(int x) { }
void run() { }
}
class Sub extends Base {
Sub() { super(42); } // 必须第一行调父构造
Sub(int n) { this(); } // 构造器互调也用 this/super
@Override void run() { super.run(); }
}
interface A { void a(); }
interface B { void b(); }
class C implements A, B { // 多实现
public void a() {} public void b() {}
}
interface C2 extends A, B {} // 接口可多继承注意事项
- 父类没有无参构造器时,子类构造器必须显式调 super(…),否则编译错
- super() 与 this() 必须是构造器第一条语句,且不能同时出现
- @Override 不是必需的但强烈建议——写错签名时编译器会报错,而非静默变成新方法
- 返回值协变:子类覆盖方法可返回更具体的类型(如 Object→String)
10. final – 终态
描述
修饰变量=引用不可重赋值(内容仍可变)、方法=不可被子类覆盖、类=不可被继承、参数=不可重赋值。final 与「不可变」不是一回事。
语法和示例
final int X = 1;
// X = 2; // 编译错误
final List<String> list = new ArrayList<>();
list.add("a"); // 合法!final 只管引用
// list = new ArrayList<>(); // 编译错误
final class Util {} // 不可继承
class Base {
final void hook() {} // 子类不可覆盖
}
// 正确的不变量:字段 final + 类型本身不可变
final class Money {
private final long cents; // 不可变
Money(long c) { cents = c; }
}注意事项
- final 修饰引用类型只保证「引用不变」,对象内容仍可变——要真不可变需所有字段 final 且无可变状态
- final 字段必须初始化:声明处、构造器内、或实例初始化块
- final 局部变量可用于匿名类/闭包捕获(Java 8+ 只要 effectively final 也可)
- static final 编译期常量(基本类型/字符串)会内联到调用处——改值后需重新编译所有依赖类
11. float / double – 浮点精度
描述
IEEE 754 二进制浮点:无法精确表示 0.1、0.2 这类十进制小数。比较用容差,算钱用 BigDecimal。float 约 7 位有效数字,double 约 15-16 位。
语法和示例
System.out.println(0.1 + 0.2); // 0.30000000000000004
System.out.println(0.1 + 0.2 == 0.3); // false!
// 数值比较加容差
double a = 0.1 + 0.2, b = 0.3;
Math.abs(a - b) < 1e-9;
// 精确计算用 BigDecimal(字符串构造!)
var p = new BigDecimal("0.1").add(new BigDecimal("0.2"));
p.equals(new BigDecimal("0.3")); // true
// 特殊值
Double.isNaN(0.0 / 0.0); // true
Double.isInfinite(1.0 / 0.0); // true注意事项
- 永远不要用 == 比较浮点数;也不要 compareTo 直接比计算结果
- BigDecimal(double) 构造器有坑(new BigDecimal(0.1) 得到 0.1000000000000000055…),必须用字符串构造
- 金额/税率/汇率一律 BigDecimal;科学计算可用 double
- float 精度仅约 7 位,累加大量数据时误差显著——统计用 double 或 Kahan 求和
12. for / while / do – 循环
描述
for(三段式)、while(先判)、do-while(至少执行一次)、增强 for(迭代器/数组语法糖)。迭代中删除元素必须用 Iterator.remove 或 removeIf。
语法和示例
for (int i = 0; i < 10; i++) { }
for (String s : list) { } // 增强 for
while (it.hasNext()) { it.next(); }
do { v = next(); } while (v < 0); // 至少一次
// 倒序
for (int i = list.size() - 1; i >= 0; i--) {}
// 安全删除(否则 ConcurrentModificationException)
for (var it = list.iterator(); it.hasNext(); ) {
if (stale(it.next())) it.remove();
}
list.removeIf(this::stale); // 等价且更简洁注意事项
- for-each 遍历中修改集合(add/remove)会抛 ConcurrentModificationException
- 数组/集合的 size/length 在循环条件里每次求值——大循环可提出变量
- do-while 结尾必须有分号
- 无限循环写 while(true) 比 for(;;) 可读性更好;记得内部 break
13. if / else – 条件与模式匹配
描述
标准条件分支;三元 ?: 是表达式;16+ 支持 instanceof 模式匹配(判断+绑定一步);21+ 的 switch 模式可做类型分发。
语法和示例
int max = a > b ? a : b;
if (x instanceof String s && s.length() > 3) { // 16+ 自动绑定
use(s);
}
if (obj instanceof Integer i && i > 0) { }
// 21+ 模式 switch(类型分发)
String desc = switch (obj) {
case Integer i -> "int " + i;
case String s when s.isEmpty() -> "空串";
case String s -> "串 " + s.length();
case null -> "null";
default -> "其他";
};注意事项
- 三元表达式两分支类型需兼容(否则会提升为公共父类型或 Object)
- instanceof 模式变量作用域受 && 短路控制——s 只在条件为真时可见
- 不要用 == 比较包装类型(Integer 缓存导致大小值行为不同),用 equals 或先拆箱
- 嵌套 if 超过 3 层考虑提前 return(卫语句)或 switch 模式
14. import / package – 包与导入
描述
package 声明文件归属(每文件一条,首行);import 引入其他包的公开类型;* 只导入本包所有类不含子包;static import 引入静态成员。
语法和示例
package com.example.app.service; // 必须在首行(注释除外)
import java.util.List;
import java.util.*; // 本包全部类(不含子包)
import static java.lang.Math.max; // 静态导入(少用)
import static java.util.stream.Collectors.*;
public class UserService {
int m = max(1, 2); // 无需 Math.max
}注意事项
- 通配符 import 不影响性能(编译期解析),但会降低可读性——团队通常禁止
- java.lang.* 自动导入(String/System/Math 无需 import)
- 同名类冲突必须用全限定名 new java.util.Date() 或只 import 一个
- 9+ 模块系统下,包还需被所在模块 exports 才能被外部 import
15. instanceof – 类型判断
描述
判断对象是否为某类/接口/数组类型;null 恒为 false。16+ 支持模式变量自动转换。
语法和示例
if (obj instanceof String) { String s = (String) obj; } // 老写法
if (obj instanceof String s) { use(s); } // 16+ 模式
if (obj instanceof int[] arr) { } // 数组类型
if (obj instanceof List<?> l) { } // 泛型擦除:不能 List<String>
null instanceof Object; // false注意事项
- null 对任何类型 instanceof 都返回 false(所以常用来做空判的前置)
- 泛型类型参数不可判断:obj instanceof List 编译错(擦除后无此信息)
- 子类 instanceof 父类为 true;反过来不一定
- 大量 instanceof 链通常意味着该用多态或 sealed + switch 模式
16. new – 实例化
描述
创建对象实例;数组也必须用 new(或字面量)。new 后必调构造器;匿名类 new Iface(){} 是「定义+实例化」一步。
语法和示例
var p = new Point(1, 2);
int[] arr = new int[10]; // 默认值 0
String[] names = {"a", "b"}; // 字面量形式
List<String> list = new ArrayList<>(16); // 可指定初始容量
Runnable r = new Runnable() { // 匿名类
public void run() { }
};
Runnable lam = () -> {}; // lambda 更简洁
// 8+ 可省略类型参数(菱形推断)
Map<String, List<Integer>> m = new HashMap<>();注意事项
- 数组 new int[10] 元素有默认值(0/false/null),不是未定义
- new 的对象在堆上;逃逸分析可栈上分配(JIT 优化,非语言保证)
- 匿名类捕获外部局部变量要求 effectively final
- 构造器里别调可被子类覆盖的方法(子类字段可能尚未初始化)
17. private / protected / public – 访问控制
描述
四级可见性:private(本类)< package-private(同包,无修饰符)< protected(同包 + 子类)< public(全部)。修饰类只能用 public/package-private。
语法和示例
package a;
public class A {
private int secret; // 仅 A 内部
int pkg; // 同包
protected int forSub; // 同包 + 子类(含跨包子类)
public int open; // 全部
}
class B { } // package-private 类
// 子类覆盖方法不能降低可见性
class C extends A {
@Override protected int forSub() { return 1; } // 不能改成 private
}注意事项
- protected 的跨包访问只对子类自身(通过 this),不能通过父类引用访问
- 覆盖方法只能扩大不能缩小可见性
- 顶层类只能 public 或 package-private(不能 private/protected)
- 9+ 模块系统还有「导出包」这一层:包未被 exports 时,public 也不可见
18. return – 返回
描述
从方法返回;void 方法可裸 return 提前退出;构造器无返回类型且不能 return 值。lambda 的 return 只从 lambda 体返回。
语法和示例
int f(boolean fast) {
if (fast) return 0; // 卫语句提前退出
return compute();
}
void g(int x) {
if (x < 0) return; // 提前退出,不返回值
process(x);
}
// lambda 的 return 只退出 lambda
list.forEach(x -> { if (x == null) return; use(x); });注意事项
- finally 里的 return 会覆盖 try 里的 return(也是吞异常的元凶)
- 返回集合时优先返回空集合而非 null(Collections.emptyList())
- 方法返回类型声明为具体类时可返回子类;声明接口时可返回任意实现
- Optional 用于「可能没有」,不要用它包装集合(空集合本身已表达)
19. static – 静态成员
描述
属于类而非实例:静态字段全实例共享、静态方法无 this、静态嵌套类不持外部引用。静态初始化块在类加载时执行一次。
语法和示例
class Counter {
private static int total; // 全实例共享
static { total = loadFromDisk(); } // 静态初始化块(类加载一次)
static int next() { return ++total; } // 不能访问实例字段
static final int MAX = 100; // 常量
static class Helper { } // 静态嵌套类(不持外部引用)
class Inner { } // 内部类(隐含持外部 this)
}注意事项
- 静态方法里不能直接用 this/super,也不能访问实例字段
- 静态字段在类加载时初始化,晚于静态块顺序执行
- 并发下静态可变字段需同步(AtomicInteger 或 synchronized)
- 静态嵌套类 vs 内部类:前者无外部引用(不会内存泄漏),优先用它
20. strictfp – 严格浮点
描述
约束浮点运算严格遵循 IEEE 754(禁止扩展精度)。17+ 后所有浮点运算默认严格,此关键字已无实际效果。
语法和示例
strictfp double calc() {
return 0.1 + 0.2; // 各平台结果一致
}
// 17+ 默认严格,可省略注意事项
- JDK 17 起 JEP 306 恢复了「始终严格」语义,strictfp 变成无操作
- 历史背景:x87 的 80 位扩展精度曾导致跨平台结果不一致
- 新代码不必写它;老代码可安全删除
21. super – 父类引用
描述
调用父类构造器、方法或字段。内部类里 Outer.super.method() 可指定外部类父方法。
语法和示例
class Base {
Base() {}
void run() { System.out.println("base"); }
}
class Sub extends Base {
Sub() { super(); } // 调父构造(必须第一行)
@Override void run() {
super.run(); // 先跑父类逻辑
extra();
}
}
// 内部类访问外部类的父类方法
class Outer extends Base {
class In {
void f() { Outer.super.run(); }
}
}注意事项
- super() 与 this() 互斥且必须第一行
- super.字段 访问父类字段(父类字段被子类同名遮蔽时用)
- 父类方法为 private 时不可被子类 super 调用(不可见)
- 多层继承时 super 只指直接父类,不是「所有祖先」
22. synchronized – 同步
描述
方法或代码块互斥执行,隐式获取/释放监视器锁。实例方法锁 this,静态方法锁 Class 对象,代码块可指定任意锁对象。
语法和示例
class Safe {
private int n;
synchronized void inc() { n++; } // 锁 this
void inc2() { synchronized (this) { n++; } } // 等价
private final Object lock = new Object();
void better() { synchronized (lock) { n++; } } // 锁专用对象(推荐)
static synchronized void reset() { } // 锁 Safe.class
}注意事项
- 锁粒度越大争用越严重:优先锁私有 final 对象,别锁 this/Class
- synchronized 可重入(同一线程可重复获取),不会自锁死
- 不要在锁内做 IO/网络调用——会把所有竞争者拖住
- 高并发读写场景用 ReentrantReadWriteLock 或 StampedLock;计数用 AtomicInteger
- 虚拟线程(21+)里 synchronized 内阻塞会 pin 载体线程,优先用 ReentrantLock
23. this – 当前实例
描述
引用当前对象:区分字段与参数、构造器链式调用 this(…)、返回自身实现流式 API、内部类引用外部实例 Outer.this。
语法和示例
class A {
private final int x;
A(int x) { this.x = x; } // 区分参数与字段
A() { this(0); } // 构造器互调(必须第一行)
A self() { return this; } // 流式 API
class In { int outerX() { return A.this.x; } } // 内部类访问外部
}注意事项
- this() 与 super() 互斥且必须第一条语句
- 静态上下文中不能出现 this
- 内部类未加限定时的 this 指内部类自身,访问外部用 Outer.this
- builder 模式的方法返回 this 时注意别返回错类型(泛型自引用需 >)
24. throw / throws – 抛出与声明
描述
throw 实际抛出异常对象;throws 在方法签名声明「可能抛出的受检异常」,由调用方处理。非受检(RuntimeException/Error)无需声明。
语法和示例
// 受检异常必须声明
int parse(String s) throws java.text.ParseException {
if (s == null) throw new IllegalArgumentException("null"); // 非受检,无需声明
return Integer.parseInt(s);
}
// 异常链保留原因
try { risky(); }
catch (IOException e) {
throw new BaseException("包装", e); // 或 new RuntimeException(e)
}注意事项
- throws 只声明受检异常;声明 RuntimeException 虽合法但无意义
- 包装异常必须传 cause,否则原始堆栈信息丢失
- throws 子类可声明更少的受检异常(不能更多)
- 不要 throw null(会抛 NPE)
- 业务异常建议继承 RuntimeException,避免污染全链路签名
25. transient – 不参与序列化
描述
字段加 transient 后默认序列化会跳过它;反序列化后该字段为默认值(null/0)。用于不可序列化的资源(连接、流、缓存)。
语法和示例
class Session implements java.io.Serializable {
private String userId;
private transient java.net.Socket conn; // 不序列化
private transient Cache cache;
// 需要自定义逻辑时实现 writeObject/readObject
private void writeObject(java.io.ObjectOutputStream out)
throws IOException {
out.defaultWriteObject();
}
}注意事项
- transient 只影响默认序列化;Externalizable 需自己控制
- static 字段本就不序列化,无需 transient
- 反序列化后 transient 字段是默认值,需自行恢复(readObject 里重建)
- 现代项目多用 JSON(Jackson 用 @JsonIgnore)而非原生序列化
26. volatile – 可见性
描述
保证写操作立即对其他线程可见、禁止指令重排;不保证复合操作原子性。适合「一个线程写、多线程读」的状态标志。
语法和示例
class Worker {
private volatile boolean running = true; // 其他线程立即可见
void stop() { running = false; }
void loop() {
while (running) { doWork(); } // 每次读主存
}
// 反例:volatile 不能保证原子
private volatile int count;
void inc() { count++; } // 仍然丢更新!
}注意事项
- count++ 是「读-改-写」三步,volatile 不保证原子——用 AtomicInteger
- volatile 禁止重排,可实现双重检查锁(DCL)的单例模式
- 比 synchronized 轻量(无锁竞争),但仍会阻止 CPU 缓存优化
- 适用于状态标志、一次性发布(写一次读多次)场景
27. true / false / null – 字面量
描述
布尔字面量与 null 引用字面量。技术上不是关键字(是字面量),但同样不能作标识符。
语法和示例
boolean ok = true; // 只能 true/false
String s = null; // 空引用
Object o = (String) null; // 合法但无意义(编译期就知是 null)
// Integer i = null; i.intValue(); // 拆箱 NPE
// null 参与运算/方法调用必 NPE注意事项
- null 不是类型,可赋给任何引用类型;不能赋给基本类型
- 包装类为 null 时自动拆箱会抛 NPE(三元表达式混用 Integer 与 int 时也拆箱)
- Optional 比返回 null 更能表达意图(但不要用 Optional 包装集合/字段)
- 21+ switch 支持 case null,替代手写 if (x == null)