Appearance
12.3 代码块
代码块的概念
代码块是用大括号 {} 包围的一段代码,在 Java 中主要有四种类型的代码块:
- 普通代码块
- 构造代码块
- 静态代码块
- 同步代码块
代码块的类型
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 中,代码块的执行顺序如下:
- 静态代码块(类加载时执行,只执行一次)
- 构造代码块(创建对象时执行,每次创建对象都会执行)
- 构造方法(创建对象时执行,每次创建对象都会执行)
示例:
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
}
}最佳实践
静态代码块:用于初始化静态属性,特别是需要复杂初始化的情况
构造代码块:用于多个构造方法中重复的代码,提高代码复用性
普通代码块:用于控制变量的作用域,避免变量名冲突
同步代码块:用于实现线程同步,保证多线程环境下的安全性
异常处理:在静态代码块中处理异常,避免类加载失败
执行顺序:了解代码块的执行顺序,确保代码的正确性
总结
代码块是 Java 中一种重要的语法结构,主要包括四种类型:
普通代码块:直接在方法或语句块中定义,用于控制变量的作用域
构造代码块:在类中定义,在创建对象时执行,每次创建对象都会执行一次
静态代码块:在类中使用
static关键字修饰,在类加载时执行,只执行一次同步代码块:在方法中使用
synchronized关键字修饰,用于实现线程同步
代码块的执行顺序:
- 静态代码块(类加载时执行,只执行一次)
- 构造代码块(创建对象时执行,每次创建对象都会执行)
- 构造方法(创建对象时执行,每次创建对象都会执行)
通过合理使用代码块,可以提高代码的可读性、可维护性和安全性。
