Skip to content

12.3 代码块

代码块的概念

代码块是用大括号 {} 包围的一段代码,在 Java 中主要有四种类型的代码块:

  1. 普通代码块
  2. 构造代码块
  3. 静态代码块
  4. 同步代码块

代码块的类型

1. 普通代码块

普通代码块是直接在方法或语句块中定义的代码块,用于控制变量的作用域。

示例:

java
public class NormalBlockExample {
    public static void main(String[] args) {
        // 普通代码块 1
        {
            int x = 10;
            System.out.println("x in block 1: " + x);
        }
        
        // 普通代码块 2
        {
            int y = 20;
            System.out.println("y in block 2: " + y);
        }
        
        // 错误:x 在代码块外不可见
        // System.out.println("x outside block: " + x);
        
        // 错误:y 在代码块外不可见
        // System.out.println("y outside block: " + y);
    }
}

2. 构造代码块

构造代码块是在类中定义的代码块,在创建对象时执行,每次创建对象都会执行一次。

示例:

java
public class ConstructorBlockExample {
    private String name;
    private int age;
    
    // 构造代码块
    {
        System.out.println("构造代码块执行");
        name = "Unknown";
        age = 0;
    }
    
    // 无参构造方法
    public ConstructorBlockExample() {
        System.out.println("无参构造方法执行");
    }
    
    // 有参构造方法
    public ConstructorBlockExample(String name, int age) {
        System.out.println("有参构造方法执行");
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public int getAge() {
        return age;
    }
    
    public static void main(String[] args) {
        System.out.println("创建第一个对象:");
        ConstructorBlockExample obj1 = new ConstructorBlockExample();
        System.out.println("Name: " + obj1.getName() + ", Age: " + obj1.getAge());
        
        System.out.println("\n创建第二个对象:");
        ConstructorBlockExample obj2 = new ConstructorBlockExample("John", 30);
        System.out.println("Name: " + obj2.getName() + ", Age: " + obj2.getAge());
    }
}

3. 静态代码块

静态代码块是在类中使用 static 关键字修饰的代码块,在类加载时执行,只执行一次。

示例:

java
public class StaticBlockExample {
    private static int staticVar;
    private int instanceVar;
    
    // 静态代码块
    static {
        System.out.println("静态代码块执行");
        staticVar = 100;
    }
    
    // 构造代码块
    {
        System.out.println("构造代码块执行");
        instanceVar = 200;
    }
    
    // 构造方法
    public StaticBlockExample() {
        System.out.println("构造方法执行");
    }
    
    public static void main(String[] args) {
        System.out.println("创建第一个对象:");
        StaticBlockExample obj1 = new StaticBlockExample();
        System.out.println("staticVar: " + staticVar + ", instanceVar: " + obj1.instanceVar);
        
        System.out.println("\n创建第二个对象:");
        StaticBlockExample obj2 = new StaticBlockExample();
        System.out.println("staticVar: " + staticVar + ", instanceVar: " + obj2.instanceVar);
    }
}

4. 同步代码块

同步代码块是在方法中使用 synchronized 关键字修饰的代码块,用于实现线程同步。

示例:

java
public class SynchronizedBlockExample {
    private int count = 0;
    private Object lock = new Object();
    
    public void increment() {
        // 同步代码块
        synchronized (lock) {
            count++;
            System.out.println("Count: " + count);
        }
    }
    
    public static void main(String[] args) {
        SynchronizedBlockExample example = new SynchronizedBlockExample();
        
        // 创建两个线程
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                example.increment();
            }
        });
        
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                example.increment();
            }
        });
        
        // 启动线程
        thread1.start();
        thread2.start();
    }
}

代码块的执行顺序

在 Java 中,代码块的执行顺序如下:

  1. 静态代码块(类加载时执行,只执行一次)
  2. 构造代码块(创建对象时执行,每次创建对象都会执行)
  3. 构造方法(创建对象时执行,每次创建对象都会执行)

示例:

java
public class BlockExecutionOrder {
    // 静态代码块 1
    static {
        System.out.println("静态代码块 1 执行");
    }
    
    // 静态代码块 2
    static {
        System.out.println("静态代码块 2 执行");
    }
    
    // 构造代码块 1
    {
        System.out.println("构造代码块 1 执行");
    }
    
    // 构造代码块 2
    {
        System.out.println("构造代码块 2 执行");
    }
    
    // 构造方法
    public BlockExecutionOrder() {
        System.out.println("构造方法执行");
    }
    
    public static void main(String[] args) {
        System.out.println("创建第一个对象:");
        BlockExecutionOrder obj1 = new BlockExecutionOrder();
        
        System.out.println("\n创建第二个对象:");
        BlockExecutionOrder obj2 = new BlockExecutionOrder();
    }
}

代码块的应用场景

1. 初始化操作

静态代码块:用于初始化静态属性,特别是需要复杂初始化的情况。

示例:

java
public class StaticBlockInitialization {
    private static Map<String, String> configMap;
    
    // 静态代码块初始化配置
    static {
        configMap = new HashMap<>();
        configMap.put("database.url", "jdbc:mysql://localhost:3306/test");
        configMap.put("database.username", "root");
        configMap.put("database.password", "123456");
        System.out.println("配置初始化完成");
    }
    
    public static String getConfig(String key) {
        return configMap.get(key);
    }
    
    public static void main(String[] args) {
        System.out.println("Database URL: " + getConfig("database.url"));
        System.out.println("Database Username: " + getConfig("database.username"));
        System.out.println("Database Password: " + getConfig("database.password"));
    }
}

2. 代码复用

构造代码块:用于多个构造方法中重复的代码。

示例:

java
public class ConstructorBlockReuse {
    private String name;
    private int age;
    private String gender;
    
    // 构造代码块,用于初始化共同的属性
    {
        System.out.println("初始化对象");
        gender = "Unknown";
    }
    
    // 无参构造方法
    public ConstructorBlockReuse() {
        name = "Unknown";
        age = 0;
    }
    
    // 有参构造方法
    public ConstructorBlockReuse(String name) {
        this.name = name;
        age = 0;
    }
    
    // 有参构造方法
    public ConstructorBlockReuse(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public int getAge() {
        return age;
    }
    
    public String getGender() {
        return gender;
    }
    
    public static void main(String[] args) {
        ConstructorBlockReuse obj1 = new ConstructorBlockReuse();
        System.out.println("Obj1: Name=" + obj1.getName() + ", Age=" + obj1.getAge() + ", Gender=" + obj1.getGender());
        
        ConstructorBlockReuse obj2 = new ConstructorBlockReuse("John");
        System.out.println("Obj2: Name=" + obj2.getName() + ", Age=" + obj2.getAge() + ", Gender=" + obj2.getGender());
        
        ConstructorBlockReuse obj3 = new ConstructorBlockReuse("Jane", 25);
        System.out.println("Obj3: Name=" + obj3.getName() + ", Age=" + obj3.getAge() + ", Gender=" + obj3.getGender());
    }
}

3. 控制变量作用域

普通代码块:用于控制变量的作用域,避免变量名冲突。

示例:

java
public class VariableScopeExample {
    public static void main(String[] args) {
        // 代码块 1
        {
            int x = 10;
            System.out.println("x in block 1: " + x);
        }
        
        // 代码块 2,使用相同的变量名
        {
            int x = 20;
            System.out.println("x in block 2: " + x);
        }
        
        // 代码块外的变量
        int x = 30;
        System.out.println("x outside blocks: " + x);
    }
}

4. 线程同步

同步代码块:用于实现线程同步,保证多线程环境下的安全性。

示例:

java
public class ThreadSafeCounter {
    private int count = 0;
    private Object lock = new Object();
    
    public void increment() {
        synchronized (lock) {
            count++;
        }
    }
    
    public void decrement() {
        synchronized (lock) {
            count--;
        }
    }
    
    public int getCount() {
        synchronized (lock) {
            return count;
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        ThreadSafeCounter counter = new ThreadSafeCounter();
        
        // 创建多个线程同时操作计数器
        Thread[] threads = new Thread[1000];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    counter.increment();
                }
            });
            threads[i].start();
        }
        
        // 等待所有线程完成
        for (Thread thread : threads) {
            thread.join();
        }
        
        System.out.println("Final count: " + counter.getCount()); // 应该输出 1000000
    }
}

常见问题

1. 静态代码块中的异常处理

症状:静态代码块中的异常如果不处理,会导致类加载失败

解决方案:在静态代码块中使用 try-catch 处理异常

示例:

java
public class StaticBlockException {
    private static File file;
    
    static {
        try {
            file = new File("config.properties");
            // 尝试读取文件
            if (!file.exists()) {
                throw new FileNotFoundException("Config file not found");
            }
        } catch (FileNotFoundException e) {
            System.err.println("Error: " + e.getMessage());
            // 提供默认值
            file = null;
        }
    }
    
    public static void main(String[] args) {
        System.out.println("File: " + file);
    }
}

2. 代码块执行顺序错误

症状:静态属性未初始化就被使用

解决方案:了解代码块的执行顺序,确保静态属性在使用前被初始化

示例:

java
public class BlockOrderExample {
    // 错误:在静态代码块前使用静态属性
    // public static int value = getValue();
    
    private static int staticVar;
    
    // 静态代码块
    static {
        staticVar = 100;
        System.out.println("Static block executed");
    }
    
    // 正确:在静态代码块后使用静态属性
    public static int value = getValue();
    
    private static int getValue() {
        return staticVar;
    }
    
    public static void main(String[] args) {
        System.out.println("Value: " + value);
    }
}

3. 构造代码块与构造方法的执行顺序

症状:构造代码块中的初始化被构造方法覆盖

解决方案:了解构造代码块和构造方法的执行顺序,构造代码块先执行,然后构造方法执行

示例:

java
public class ConstructorOrderExample {
    private String name;
    
    // 构造代码块
    {
        name = "Default Name";
        System.out.println("Constructor block: name = " + name);
    }
    
    // 构造方法
    public ConstructorOrderExample() {
        name = "Constructor Name";
        System.out.println("Constructor: name = " + name);
    }
    
    public String getName() {
        return name;
    }
    
    public static void main(String[] args) {
        ConstructorOrderExample obj = new ConstructorOrderExample();
        System.out.println("Final name: " + obj.getName()); // 输出 Constructor Name
    }
}

最佳实践

  1. 静态代码块:用于初始化静态属性,特别是需要复杂初始化的情况

  2. 构造代码块:用于多个构造方法中重复的代码,提高代码复用性

  3. 普通代码块:用于控制变量的作用域,避免变量名冲突

  4. 同步代码块:用于实现线程同步,保证多线程环境下的安全性

  5. 异常处理:在静态代码块中处理异常,避免类加载失败

  6. 执行顺序:了解代码块的执行顺序,确保代码的正确性

总结

代码块是 Java 中一种重要的语法结构,主要包括四种类型:

  1. 普通代码块:直接在方法或语句块中定义,用于控制变量的作用域

  2. 构造代码块:在类中定义,在创建对象时执行,每次创建对象都会执行一次

  3. 静态代码块:在类中使用 static 关键字修饰,在类加载时执行,只执行一次

  4. 同步代码块:在方法中使用 synchronized 关键字修饰,用于实现线程同步

代码块的执行顺序:

  1. 静态代码块(类加载时执行,只执行一次)
  2. 构造代码块(创建对象时执行,每次创建对象都会执行)
  3. 构造方法(创建对象时执行,每次创建对象都会执行)

通过合理使用代码块,可以提高代码的可读性、可维护性和安全性。

© 2026 编程马·菜鸟教程 版权所有