3.6 代码块
用 { } 包起来的一段代码就是代码块。按位置分三种:局部代码块(方法里,限制变量寿命)、构造代码块(方法外,每次 new 都跑)、静态代码块(static { },全程序只跑一次)——考试常考它们的执行顺序。
1. 代码块是什么——你其实早就在写
从 1.3 第一行代码起你就天天和 { } 打交道:类有 { }、方法有 { }、if 和 for 有 { }。一对花括号包起来的独立区域,就叫代码块。
花括号有个天生的规矩:它是变量作用的边界(2.2 学的作用域)——变量在哪个 { } 里定义,出这个 { } 就消失。
本节要学的不是这个基本盘,而是三种"独立存在"的代码块——它们不在任何方法里(或正是为了管住方法里的变量),各有各的出场时机。
2. 局部代码块——方法里的"临时车间"
在方法内部单独写一对 { }:
public static void main(String[] args) {
System.out.println("开始");
{ // 局部代码块
int temp = 999;
System.out.println("临时计算:" + temp * 2);
} // temp 在这里消亡
// System.out.println(temp); // 编译报错:找不到符号 temp
System.out.println("结束");
}
作用就一条:给临时变量划个短命区——大段逻辑中某几个变量只在中间步骤有用,装进局部代码块,出块即释放,避免名字污染整个方法。
局部代码块日常用得不多(一个方法本来就该短小,需要隔离时通常直接拆成新方法)。但它揭示了核心规则:{ } 就是变量世界的围墙——这条规则贯穿后面两种代码块。
3. 构造代码块——每次 new 的"开场白"
写在类里、方法外的 { }:
public class Car {
private String brand;
private double price;
{ // 构造代码块:不写 static,光秃秃一对 { }
System.out.println("一辆新车进入装配线");
}
public Car() {
System.out.println("无参构造完成");
}
public Car(String brand, double price) {
this.brand = brand;
this.price = price;
System.out.println("带参构造完成");
}
}
new 两次的输出:
一辆新车进入装配线 ← 构造代码块
无参构造完成 ← 构造方法
一辆新车进入装配线 ← 又是构造代码块(每次 new 都跑)
带参构造完成
两条规律:
- 每次 new 都执行,无一例外
- 总是先于构造方法——所以它常被叫作"所有构造方法的开场白"
用途:多个构造方法里有公共的初始化动作时,抽到构造代码块里,只写一遍。比如"每次造车都要贴出厂编号"这种所有出生方式都做的事。
3.5 的 this(...) 构造互调也能收拢公共逻辑(转发到全参构造)。构造代码块是更老的办法——不管调哪个构造都自动跑,连转发都省了。现代代码里它用得不算多,但读别人代码、应付考试必须认识。
4. 静态代码块——类的"开机自检"
在构造代码块前加 static:
public class Car {
static {
System.out.println("Car 类加载完毕,开机自检");
}
}
它的出场时机和前两种完全不同:不属于任何对象,属于类本身——在类第一次被使用(第一次 new、第一次访问它的成员)时执行,全程序从头到尾只跑一次。
public static void main(String[] args) {
System.out.println("main 开始");
new Car();
new Car();
System.out.println("main 结束");
}
输出:
main 开始
Car 类加载完毕,开机自检 ← 第一次 new 前才执行,且只有这一次
(构造代码块、构造方法的输出省略)
main 结束
static 意思是"属于类的、大家共用的"——所以静态代码块跟着类走而不是跟着对象走:类一辈子加载一次,它就一辈子跑一次。static 的完整面貌(静态属性、静态方法、为什么 main 是 static)是后面专门的一节,这里只需记住:静态代码块 = 类的开机自检,仅一次。
真实用途举例:Java 程序连数据库前要先"加载驱动",这种一次性准备工作就放在静态代码块里——保证要用前一定就绪,且绝不做第二遍。
5. 执行顺序——本节的考试中心
三种块凑齐时的完整顺序(上面那张图):
第一次用到类:
① 静态代码块 (仅这一次,跟类走)
每次 new 时:
② 构造代码块 (每次都跑,先于构造方法)
③ 构造方法 (收尾,真正装值)
口诀:静态一次 → 构造块每次 → 构造方法收尾。
同一种块有多个时(不推荐但合法),按书写的先后顺序执行。
6. 动手部分:亲眼看一遍执行顺序
第 1 步:在 IDEA02 里新建类 Game:
public class Game {
static {
System.out.println("① 静态代码块:加载游戏资源");
}
{
System.out.println("② 构造代码块:创建对局环境");
}
public Game() {
System.out.println("③ 无参构造:开局");
}
public Game(String mode) {
System.out.println("③ 带参构造:开局(模式 " + mode + ")");
}
}
第 2 步:新建测试类 TestGame:
public class TestGame {
public static void main(String[] args) {
System.out.println("main 开始");
Game g1 = new Game();
Game g2 = new Game("排位");
System.out.println("main 结束");
}
}
看到什么算成功:控制台共 7 行,顺序必须是——
main 开始
① 静态代码块:加载游戏资源
② 构造代码块:创建对局环境
③ 无参构造:开局
② 构造代码块:创建对局环境
③ 带参构造:开局(模式 排位)
main 结束
① 只出现一次(第一次 new 前才触发),② 每次都出现且总在 ③ 前面——这三条规律亲眼看一遍,比背十遍口诀都牢。
三个 30 秒实验:
- 在
TestGame.main里不 new,只写System.out.println(Game.class.getName());——静态代码块也会跑!因为它访问了 Game 类(触发类加载),静态块跟类走,不跟对象走 - 把构造代码块里的打印挪到构造方法后面书写(位置在类的下方)——输出不变,顺序由种类决定,与书写位置无关(静态块同理)
- 在 Game 里写两个静态代码块——按书写顺序各跑一次,总共各一遍
7. 常见误区
顺序由种类决定(静态 → 构造块 → 构造方法),与书写位置无关。写在类末尾的构造代码块照样先于写在类开头的构造方法执行。
恰恰相反——它跟类走不跟对象走,类一辈子只加载一次,它就只跑一次。第二次、第三次 new 时它装聋作哑。跑一次的是构造代码块。
大多数情况下你先 new 了才看到它跑,容易以为它在 main 前执行。实际触发时机是"类第一次被使用"——main 里如果不碰这个类,静态块根本不执行(实验 1 验证了这点)。顺序上它一定早于该类的任何对象出生,但不一定早于 main 开始。
出 { } 即消亡,块外访问直接编译报错"找不到符号"。这正是它存在的意义:给临时变量划短命区。
不能。各自的 { } 都是独立的围墙:局部块的变量出块即死;构造块/静态块里的变量也只在自己块内有效(静态块连实例属性都碰不了——它执行时对象还不存在,这是 static 的一课,后面收网)。
8. 自测题
局部代码块在方法里,执行到就跑(变量出块即死);构造代码块在类里方法外,每次 new 都跑且先于构造方法;静态代码块加 static,类第一次被使用时跑,全程序仅一次。
静态块 1 次(第一次 new 前触发类加载)、构造块 3 次、构造方法 3 次。口诀:静态一次 → 构造块每次 → 构造方法收尾。
不会。执行顺序由块的种类决定,与书写位置无关——构造代码块永远先于构造方法。它就是"所有构造方法的开场白",写在哪儿都改不了身份。
静态块做类级别的一次性准备(如加载数据库驱动——全程序做一次就够);构造块做每个对象的公共初始化(如每辆车都贴出厂编号——每 new 一次都要做)。一个跟着类走、一次;一个跟着对象走、每次。
不 new 也可能执行——只要 Game 类第一次被使用就触发类加载。比如访问它的静态成员、用 Game.class 反射拿类信息,都会让静态块跑起来。它绑定的单位是"类",不是"对象"。
9. 下一步学什么
- ☑
3.6 代码块✅ 三种{ }各就各位,执行顺序口诀到手 - ☑
3.7 static关键字✅ 已完成——静态块"仅一次"、static 里没有 this、main 的秘密,三处伏笔全部收网,详见 3.7 static关键字
相关笔记
- 3.4 构造方法 ← 构造代码块是它的"开场白"
- 3.5 this关键字 ← 收拢公共初始化的另一条路(构造互调)
- 2.2 Java中的变量 ←
{ }是作用域边界,本节的全套根基 - 3.2 类与对象 ← 类与对象的两层世界,静态块属于"类"那一层
- 📇 Java基础 · 索引
- 🏠 返回主页