Skip to content

代码块

代码块是 Java 中用大括号 {} 包围的代码区域,分为静态代码块实例代码块

静态代码块

基本语法

java
public class StaticBlockDemo {

    static {
        System.out.println("静态代码块 - 类加载时执行");
    }

    public StaticBlockDemo() {
        System.out.println("构造方法");
    }

    public static void main(String[] args) {
        System.out.println("--- 创建第一个对象 ---");
        new StaticBlockDemo();
        System.out.println("--- 创建第二个对象 ---");
        new StaticBlockDemo();
    }
}

输出:

静态代码块 - 类加载时执行
--- 创建第一个对象 ---
构造方法
--- 创建第二个对象 ---
构造方法

特点

  1. 只执行一次:类加载时执行,无论创建多少对象
  2. 用于初始化静态资源:加载配置文件、初始化数据库连接等
java
public class DatabaseConnection {
    private static String url;
    private static String username;
    private static String password;

    // 静态代码块:初始化静态资源
    static {
        Properties props = new Properties();
        try {
            props.load(new FileInputStream("db.properties"));
            url = props.getProperty("db.url");
            username = props.getProperty("db.username");
            password = props.getProperty("db.password");
        } catch (IOException e) {
            throw new ExceptionInInitializerError(e);
        }
    }
}

实例代码块

基本语法

java
public class InstanceBlockDemo {

    private String name;

    // 实例代码块:每次 new 都执行
    {
        System.out.println("实例代码块执行");
        this.name = "default";
    }

    public InstanceBlockDemo() {
        System.out.println("构造方法");
    }

    public InstanceBlockDemo(String name) {
        this.name = name;
        System.out.println("带参构造方法");
    }

    public static void main(String[] args) {
        System.out.println("--- 创建第一个对象 ---");
        new InstanceBlockDemo();
        System.out.println("--- 创建第二个对象 ---");
        new InstanceBlockDemo("自定义");
    }
}

输出:

--- 创建第一个对象 ---
实例代码块执行
构造方法
--- 创建第二个对象 ---
实例代码块执行
带参构造方法

特点

  1. 每次 new 都执行:创建几个对象,就执行几次
  2. 在构造方法之前执行:实际执行顺序是:实例代码块 → 构造方法
  3. 可以访问实例成员:包括 private 成员

执行顺序

当一个类有静态代码块、实例代码块和构造方法时:

java
public class ExecutionOrderDemo {

    // 静态代码块
    static {
        System.out.println("1. 静态代码块");
    }

    // 实例代码块
    {
        System.out.println("2. 实例代码块");
    }

    // 构造方法
    public ExecutionOrderDemo() {
        System.out.println("3. 构造方法");
    }

    public static void main(String[] args) {
        System.out.println("=== 创建第一个对象 ===");
        new ExecutionOrderDemo();
        System.out.println("=== 创建第二个对象 ===");
        new ExecutionOrderDemo();
    }
}

输出:

1. 静态代码块
=== 创建第一个对象 ===
2. 实例代码块
3. 构造方法
=== 创建第二个对象 ===
2. 实例代码块
3. 构造方法

父子类执行顺序

当涉及继承时,顺序更复杂:

java
class Parent {
    static {
        System.out.println("父类静态代码块");
    }

    {
        System.out.println("父类实例代码块");
    }

    public Parent() {
        System.out.println("父类构造方法");
    }
}

class Child extends Parent {
    static {
        System.out.println("子类静态代码块");
    }

    {
        System.out.println("子类实例代码块");
    }

    public Child() {
        System.out.println("子类构造方法");
    }
}

public class Test {
    public static void main(String[] args) {
        System.out.println("=== 创建子类对象 ===");
        new Child();
    }
}

输出:

=== 创建子类对象 ===
父类静态代码块
子类静态代码块
父类实例代码块
父类构造方法
子类实例代码块
子类构造方法

完整顺序:

1. 父类静态代码块
2. 子类静态代码块
3. 父类实例代码块
4. 父类构造方法
5. 子类实例代码块
6. 子类构造方法

实际应用

1. 初始化配置

java
public class AppConfig {
    private static Properties properties;

    static {
        properties = new Properties();
        try {
            properties.load(AppConfig.class.getClassLoader()
                .getResourceAsStream("config.properties"));
        } catch (IOException e) {
            throw new RuntimeException("加载配置文件失败", e);
        }
    }

    public static String get(String key) {
        return properties.getProperty(key);
    }
}

2. 注册监听器

java
public class EventBus {
    private static final List<EventListener> listeners = new ArrayList<>();

    static {
        // 类加载时注册默认监听器
        listeners.add(new DefaultListener());
        listeners.add(new LoggingListener());
    }

    public static void register(EventListener listener) {
        listeners.add(listener);
    }
}

3. 初始化日志环境

java
public class LoggerFactory {
    private static boolean initialized = false;

    static {
        // 初始化日志框架配置
        System.setProperty("java.util.logging.config.file", "logging.properties");
        initialized = true;
    }

    public static Logger getLogger(Class<?> clazz) {
        return Logger.getLogger(clazz.getName());
    }
}

注意事项

1. 静态代码块只执行一次

java
public class Test {
    static {
        System.out.println("静态代码块");
    }

    public static void main(String[] args) {
        Test t1 = new Test();
        Test t2 = new Test();
        Test t3 = new Test();
        // 静态代码块只输出一次
    }
}

2. 静态代码块在类加载时执行

类加载发生在:

  • 创建对象时
  • 调用静态方法时
  • 子类加载时(会先加载父类)

3. 静态代码块抛异常会导致类加载失败

java
public class BadClass {
    static {
        // 如果这里抛异常,整个类都无法使用
        throw new Error("初始化失败");
    }
}

代码块 vs 构造方法

对比项静态代码块实例代码块构造方法
执行时机类加载时每次 new每次 new
执行次数一次每次每次
能访问什么静态成员所有成员所有成员
this/super

总结

类加载 → 静态代码块

new 对象 → 实例代码块 → 构造方法
  • 静态代码块:类加载时执行一次,用于初始化静态资源
  • 实例代码块:每次 new 都执行,在构造方法之前
  • 两者都可以用于初始化,但各有适用场景

基于 VitePress 构建