第 19 章:static 与 final 关键字
学习目标
- 掌握 static 修饰字段、方法、代码块、内部类
- 掌握 final 修饰类、方法、变量
- 理解 static 初始化顺序(高频面试题)
一、static 关键字
1.1 static 字段(类变量)
java
public class User {
private static int count = 0; // ① 类变量:所有对象共享
private String name;
public User(String name) {
this.name = name;
count++; // ② 每创建一个对象 +1
}
public static int getCount() { // ③ 静态方法访问静态字段
return count;
}
}
new User("A");
new User("B");
new User("C");
System.out.println(User.getCount()); // 3类变量 vs 实例变量:
| 维度 | 类变量(static) | 实例变量 |
|---|---|---|
| 存储位置 | 方法区 | 堆(对象内) |
| 共享 | 所有对象共享 | 每个对象独立 |
| 访问 | User.count | user.name |
1.2 static 方法(类方法)
java
public class MathUtils {
public static int max(int a, int b) { // ① 静态方法
return a > b ? a : b;
}
}
MathUtils.max(3, 5); // ✅ 通过类名直接调用,无需 new静态方法的特点:
java
public class Demo {
private int instanceField = 10;
private static int staticField = 20;
public static void staticMethod() {
System.out.println(staticField); // ✅ 访问静态字段
// System.out.println(instanceField); // ❌ 不能访问实例字段
// instanceMethod(); // ❌ 不能调用实例方法
}
public void instanceMethod() {
System.out.println(staticField); // ✅ 实例方法可访问静态
System.out.println(instanceField); // ✅
}
}原因:静态方法在类加载时存在,实例方法 / 字段要等对象创建才存在。
1.3 static 代码块(静态初始化块)
java
public class Config {
private static final Properties PROPS = new Properties();
static { // ① 类加载时执行一次
try {
PROPS.load(new FileInputStream("config.properties"));
System.out.println("配置文件加载完成");
} catch (IOException e) {
throw new RuntimeException("加载配置失败", e);
}
}
}1.4 static 初始化顺序(高频面试题)
java
public class InitOrder {
private static String staticField = initStaticField();
private String instanceField = initInstanceField();
static {
System.out.println("2. 静态代码块");
}
{
System.out.println("4. 实例代码块");
}
public InitOrder() {
System.out.println("5. 构造器");
}
private static String initStaticField() {
System.out.println("1. 静态字段初始化");
return "static";
}
private String initInstanceField() {
System.out.println("3. 实例字段初始化");
return "instance";
}
public static void main(String[] args) {
new InitOrder();
new InitOrder();
}
}输出:
1. 静态字段初始化
2. 静态代码块
3. 实例字段初始化
4. 实例代码块
5. 构造器
3. 实例字段初始化
4. 实例代码块
5. 构造器1.5 static 内部类
java
public class Outer {
private static int outerStatic = 10;
public static class Inner { // ① 静态内部类
public void hello() {
System.out.println("outerStatic = " + outerStatic); // ✅ 可访问外部静态字段
}
}
}
Outer.Inner inner = new Outer.Inner(); // ② 直接 new,无需外部实例二、final 关键字
2.1 final 变量(常量)
java
public class Constants {
public static final int MAX_COUNT = 100; // ① 全局常量
public static final String APP_NAME = "TaskFlow";
private final String name; // ② 实例常量
private final int id;
public Constants(String name, int id) {
this.name = name;
this.id = id;
}
public void test() {
final int localConst = 10; // ③ 局部常量
// localConst = 20; // ❌ 不能修改
}
}final 变量的规则:
java
// ❌ 错误:没有初始值
final int x; // 成员变量:构造器 / 初始化块 / 字段初始化中必须赋值
final int y; // 局部变量:使用前必须赋值
// ✅ 正确
final int z = 10; // 声明时初始化2.2 final 方法(不可重写)
java
public class Parent {
public final void hello() { // ① final 方法
System.out.println("Parent");
}
}
public class Child extends Parent {
// @Override // ❌ 编译报错:不能重写 final 方法
// public void hello() { }
}2.3 final 类(不可继承)
java
public final class String { ... } // String 是 final 类
public final class Math { ... }
// public class MyString extends String { ... } // ❌ 编译报错2.4 final 参数
java
public void process(final int x) { // ① 参数不可修改
// x = 10; // ❌ 编译报错
System.out.println(x);
}三、static final 常量
java
public class Constants {
public static final int MAX_COUNT = 100; // 编译时常量
public static final String DEFAULT_NAME = "Anonymous";
public static final double PI = 3.141592653589793;
}命名规范:全大写 + 下划线分隔。
四、本章小结
| 要点 | 关键 |
|---|---|
| static 字段 | 类变量,所有对象共享 |
| static 方法 | 类方法,不能访问实例成员 |
| static 块 | 类加载时执行一次 |
| 初始化顺序 | 静态(字段→块)→ 实例(字段→块→构造器) |
| final 变量 | 不可修改的常量 |
| final 方法 | 不可重写 |
| final 类 | 不可继承 |
| static final | 全局常量 |
动手练习
练习 1:基础题
创建一个 Counter 类,用 static 字段统计创建的对象数量。
练习 2:进阶题
写出以下代码的初始化顺序:
java
class Parent {
static { System.out.println("P-static"); }
{ System.out.println("P-init"); }
public Parent() { System.out.println("P-ctor"); }
}
class Child extends Parent {
static { System.out.println("C-static"); }
{ System.out.println("C-init"); }
public Child() { System.out.println("C-ctor"); }
}
// new Child();下一章:第 20 章:抽象类 →