java中的代码块

代码块的概念及分类

概念:使用{}定义的一段代码称为代码块。

分类:根据代码块定义的位置以及关键字,可分为以下四种:

(1)局部代码块

(2)构造代码块

(3)静态代码块

(4)同步代码块

一、局部代码块

局部代码块,定义在方法中,局部代码块的中的语句只在这个代码块中有效
比如下面的代码:

public class LocalCodeBlock {
    public static void main(String[] args) {
        int a=10;
        System.out.println(a);

        //局部代码块,定义在方法中,局部代码块的中的语句只在这个代码块中有效
        {
            int b=20;
            System.out.println(b);
        }

        //System.out.println(b);//b只在局部代码块中有效,代码块结束了变量b就会被释放掉,以前是为了节约内存,现在不需要这么做了
    }
}

局部代码块中的属性和方法只作用在该代码块中起作用

二、构造代码块

‌构造代码块是‌Java中一种特殊的代码块,用于在类加载时或对象创建前执行特定的初始化操作。它位于类定义中,但在任何方法之外。构造代码块的主要作用是为类的所有对象提供统一的初始化操作,确保每个对象在创建时都能执行特定的初始化逻辑。也可以将构造方法中的公共方法或者属性抽取出来,放到构造代码块中。
构造代码块在每一次创建对象时都会执行一次构造代码块。在构造方法之前执行
比如下面的代码:
定义一个学生类:

public class Student{
    private String name;
    private int age;

    /*
    public Student() {
        System.out.println("创建了有一个对象");
    }

    public Student(String name, int age) {
        System.out.println("创建了一个对象");
        this.name = name;
        this.age = age;
    }

     */

    //可以看出构造方法中有重复的语句,这种重复的就可以从构造方法中抽象出来,称为一个构造代码块。(所以,构造代码块就是写在成员位置的代码块)
    //执行时机:我们在创建本类对象的时候会先执行构造代码块,再执行构造方法
    //但是这种写法不够灵活,渐渐地被淘汰了
    {
        System.out.println("创建了一个对象");
    }

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

测试类中:

public class ConstructorCodeBlock {
    public static void main(String[] args) {
        Student student = new Student();	//创建了一个对象
    }
}

三、静态代码块

静态代码块是Java中的一个特殊代码块,用关键字"static"和大括号括起来。它位于类中,但不在任何方法内部。静态代码块在类被加载时执行,并且只会执行一次。

静态代码块的主要作用如下:

  1. 初始化静态变量:静态代码块可以用于初始化类中的静态变量。在类加载时执行,可以在代码块中对静态变量进行赋初值操作。

  2. 执行一次性初始化操作:静态代码块在类加载时只执行一次,因此可以用于执行一次性的初始化操作,例如读取配置文件、建立数据库连接等。

  3. 预加载资源:静态代码块可以在类加载时预加载一些资源,以提高程序的性能。例如,可以在静态代码块中预加载一些常用的数据,减少后续操作的延迟。

需要注意的是,静态代码块的执行顺序与它们在类中的定义顺序有关。如果有多个静态代码块,它们将按照定义的顺序依次执行。

代码如下:
定义一个学生类:

public class Student1{
    private String name;
    private int age;

    //静态代码块
    //用处:可以用来做一些对象数据的初始化
    static {
        System.out.println("代码块执行了");

    }


    public Student1() {
        System.out.println("空参构造");
    }

    public Student1(String name, int age) {
        System.out.println("带参构造");
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

测试类:

/*
    重要:
    静态代码块:
        格式:static{}
        特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发,只执行一次
 */
public class StaticCodeBlock {
    public static void main(String[] args) {
        Student1 s1 = new Student1(); //先执行静态代码块中的,且执行一次
        Student1 s2 = new Student1();   //只执行空参构造

    }
}

需要注意的是,静态代码块并不是必须的,只有在需要在类加载时执行一些初始化操作或预加载资源时才会用到。大多数情况下,我们可以通过构造函数和普通代码块来完成需要执行的操作。

四、同步代码块

主要用在多线程编程中。在Java多线程编程中,同步代码块是一种基础且强大的机制,用于控制对共享资源的并发访问,从而确保线程安全。通过使用synchronized关键字来标记代码块,可以将一段代码标记为临界区。‌当一个线程进入该临界区时,‌其他线程将被阻塞,‌直到该线程执行完临界区的代码并释放锁。‌这样可以确保在同一个时间只有一个线程能够执行临界区的代码,‌避免了多线程之间的竞争条件和数据不一致的问题。‌

同步代码块可以使用任意对象作为锁,‌通过对锁对象的加锁和解锁来实现线程的同步执行。‌使用同步代码块时,‌必须有两个或两个以上的线程,‌且同一时间只有一个线程能够执行同步代码块。‌多个线程想要同步时,‌必须共用同一把锁,‌即synchronized括号里面的对象‌。
开发者可以避免多个线程同时执行这些代码块,这对于修改共享资源或执行需要按顺序进行的操作至关重要。
同步代码块的基本语法:

synchronized(对象引用) {
    // 访问或修改共享资源的代码

下面有个例子,这个例子模拟了一个简单的计数器,‌多个线程尝试同时增加计数器的值,‌但通过使用同步代码块,‌我们确保了每次只有一个线程能够修改计数器的值。‌
定义一个Counter 类:

package com.zOOP.day7_polymorphism.tongbu;

public class Counter {
    private int count = 0;
    private final Object lock = new Object(); // 锁对象

    // 同步方法,‌增加计数器的值
    public void increment() {
        synchronized (lock) { // 使用lock对象作为锁来保护同步代码块
            count++;
            System.out.println(Thread.currentThread().getName() + " 增加cout值为: " + count);	//打印值count正确增加
        }
    }

    // 获取计数器的当前值
    public int getCount() {
        return count;
    }
}

测试类:

package com.zOOP.day7_polymorphism.tongbu;

public class Test {
    public static void main(String[] args) {

        Counter counter = new Counter();

        // 创建并启动5个线程来增加计数器
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                for (int j = 0; j < 10; j++) {
                    counter.increment();
                }
            }, "Thread-" + i).start();
        }

        // 等待所有线程执行完毕(‌这里的处理方式仅供演示)‌
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("最终的count: " + counter.getCount());//最终结果为50


    }
}

在这个例子中,‌Counter类有一个increment方法,‌该方法包含一个同步代码块,‌用于保护对count变量的访问。‌我们创建了一个锁对象lock,‌并在同步代码块中使用它。‌在测试类的main方法中,‌我们创建了5个线程,‌每个线程都会调用increment方法来增加count的值10次。‌由于同步代码块的存在,‌每次只有一个线程能够进入increment方法中的同步代码块,‌并执行增加计数器的操作。‌因此,‌尽管有多个线程在并发执行,‌但count的值总是正确地被增加,‌避免了多线程并发访问导致的数据不一致问题。‌

请注意,‌示例中的Thread.sleep(2000)仅仅是为了简单演示而加入的,‌它让主线程等待2秒以便其他线程有时间完成它们的任务。‌

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值