详细解释 Java 中的四大代码块

2,897 阅读5分钟

  Java中的代码块分为四种:普通代码块、构造代码块、静态代码块、同步代码块。代码块指的是在代码中特定位置的用花括号括起来的内容。

普通代码块


  在方法或语句中出现的{}里面的内容就被称为普通代码块,普通代码块和一般的语句执行顺序一样,由他们在代码中出现的次序决定,即——“先出现先执行”。
  但是不同的普通代码块即使在同一个方法里面定义,里面存储的方法和变量都有自己独立的作用域,但是都可以访问在自己所在花括号之外,所在方法或语句之内的内容。

public class Main {
    public static void main(String[] args) {
        int a = 1;
        {
            int b=2;
            int c=1;
            System.out.print(a);
            System.out.print(c);
        }
        {
            int c=3;
            System.out.print(c);
        }
       // System.out.print(b);这一句是不行的,b脱离作用域了
    }
}

构造代码块(实例代码块)


  直接在类中定义的而且没有加static的代码块被称为构造代码块,构造代码块在创建对象的时候被调用,每次创建对象的时候都会被调用,并且构造代码块的执行次序是优于构造函数的。
  构造代码块在每次创建对象的时候被调用

public class CodeBlock02{
    {
      //这里写在构造函数的前面,但是这并不是在构造函数之前执行的原因
      System.out.println("第一代码块");    
    }    
    public CodeBlock02(){
        System.out.println("构造方法");
        }       
        {
          //这里写在构造函数的后面,可以在结果上看到依旧是在构造函数之前执行的
          System.out.println("第二构造块");
        }
      public static void main(String[] args){
          new CodeBlock02();
          new CodeBlock02();
          // 在结果中可以看到,每次生成新对象的时候        
          new CodeBlock02(); 
    }
}

执行结果:

第一代码块
第二构造块
构造方法
第一代码块
第二构造块
构造方法
第一代码块
第二构造块
构造方法

静态代码块


  在类中定义的有static关键词的代码块被称为静态代码块,静态类被用于初始化类,为类的属性初始化,对于一个类,其对应的静态代码只会执行一次,由于JVM在加载类时会执行静态代码块,所以静态代码由于主方法执行(意思是,如果main函数定义在该类中,静态代码块也会先执行);
  如果类中包含有多个静态代码块,那么将按照“先定义的代码先执行,后定义的代码后执行”;
  静态代码块不能存在于任何的方法体内,因为本身是静态的,所以也只能访问对应类中的静态成员。

class Code{
    {
      System.out.println("Code的构造代码块");
    } 
    static{
        System.out.println("Code的静态代码块");
        }      
    public Code(){
        System.out.println("Code的构造方法");
        }
    }    
public class CodeBlock03{
     {
      System.out.println("CodeBlock03的构造代码块");    
     }
     static{
        System.out.println("CodeBlock03的静态代码块");
        }
        public CodeBlock03(){
             System.out.println("CodeBlock03的构造方法");
            }
      public static void main(String[] args){
            System.out.println("CodeBlock03的主方法");
            new Code();
            new Code();
            new CodeBlock03();
            new CodeBlock03();
          }
    }

执行结果:

//静态代码块甚至可以在main函数里的第一条语句之前执行!!!但是由于是静态的,所以只执行了一次
CodeBlock03的静态代码块
CodeBlock03的主方法
//同样由于是静态的,所以只执行了一次
Code的静态代码块
Code的构造代码块
Code的构造方法
Code的构造代码块
Code的构造方法
CodeBlock03的构造代码块
CodeBlock03的构造方法
CodeBlock03的构造代码块
CodeBlock03的构造方法

同步代码块


  这里的同步代码块指的是被Java中Synchronized关键词修饰的代码块,在Java中,Synchronized关键词不仅仅可以用来修饰代码块,与此同时也可以用来修饰类、方法,是一种线程同步机制,被Synchronized关键词修饰的代码块会被加上内置锁。显然,因为是同步代码块,因此比被Synchronized关键词修饰的方法更加颗粒化(实际上因为本身同步是一种高开销的操作,因此我们应该尽量减少被同步的内容,很很多场景,我们没有必要去同步整个方法,而只需要同步部分代码即可,也就是使用同步代码块,因此在很多场景,自己更加推崇使用同步代码块),被Synchronized关键词修饰的代码块如下:

public class CodeBlock04 implements Runnable{
    public void method(){  
        synchronized(this){  
            System.out.print("这里是同步代码块");  
        }  
    } 
    public static void main(String[] args){
        CodeBlock04 a=new CodeBlock04();
        CodeBlock04 b=new CodeBlock04();
    }
}

  当两个并发线程访问同一个对象object中的Synchronized(this)同步代码块时(不仅仅限于同一个代码块,只要是从属于同一个object),只有一个线程能够得以执行,另一个线程则处于阻塞态,只有在一个线程执行完该同步代码块之后,另外一个线程才能得以访问该同步代码块,但是对于非同步代码块,则完全不受影响。事实上,以上规则对于Java中的其他对象锁也是同样适用的。
  当然,要针对于同一个对象:

new Thread(a).start;
new Thread(a).start;
//两个从属于a的则会受到影响,而从属于b的则不会
new Thread(b).start;

  最后提一点,对于Synchronized关键词修饰静态方法和对象,可以很容易推断的是,因为静态方法是属于类而不是属于对象的,因此使用Synchronized来修饰静态方法和静态对象的时候,类下的所有对象都会被锁定。