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来修饰静态方法和静态对象的时候,类下的所有对象都会被锁定。