1. 什么是同步代码块??使用同步代码块的好处是什么??
1. 1 同步代码块
-
代码块又称为初始化块,属于类中的成员[即是类的一部分],类似于方法,将逻辑语句分装在方法体中,通过{}包围起来。
-
和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不通过对象或类显示调用,而是加载类时,或创建对象时隐形调用
-
基本语法
[修饰符]{ 代码 }; 注意: 1. 修饰符是可选的【可写可不写】,但要写的话只能写static 2. 代码块分为两类: 第一类:使用static修饰的叫做静态代码块 第二类:没有用static修饰的叫做普通代码块 3. 逻辑语句可以分为任何逻辑语句(如:输入,输出,方法调用,循环,判断等) 4. ";"号可以写上也可以不写。
1.2 为什么要用同步代码块(好处)
优点:
- 相当于另一种形式的构造器(对构造器的补充机制),可以做初始化的操作。
- 应用场景:假设在类中多个构造器中有重复语句,可以抽取到初始化代码块中,提高代码的重用性。
- 和设计模式中的"单例设计模型"有关(与static修饰符关联有奇效)。
注意:代码块与构造器的调用规则:代码块的执行是优先于构造器的。
使用代码块案例:
package 进阶.面向对象01.同步代码块;
/*
为什么要用同步代码块??? 使用同步代码块的好处是什么??
观察: 在类movie中的三个构造器中都有相同的语句,这样做比较啰嗦
如何解决: 可以思考将相同的语句放入到一个代码块中即可。
好处:使用同步代码块之后,不管调用哪个构造器,创建对象,都会先调用代码块中的内容
注意:代码块的调用要优先于构造器
*/
public class CodeBlock01 {
public static void main(String[] args) {
Movie movie = new Movie("你好");
System.out.println("=============");
Movie movie2 = new Movie("唐探3", 100, "陈思诚");
}
}
class Movie{
private String name;
private double price;//价格
private String director;
{
System.out.println("电影屏幕打开...");
System.out.println("广告开始...");
System.out.println("电影正式开始...");
}
//构造器 3个构造器->>重载
public Movie(String name){
// System.out.println("电影屏幕打开...");
// System.out.println("广告开始...");
// System.out.println("电影正式开始...");
System.out.println("Movie(String name) 被调用了。。。。");
this.name = name;
}
public Movie(String name, double price) {
// System.out.println("电影屏幕打开...");
// System.out.println("广告开始...");
// System.out.println("电影正式开始...");
this.name = name;
this.price = price;
}
public Movie(String name, double price, String director) {
// System.out.println("电影屏幕打开...");
// System.out.println("广告开始...");
// System.out.println("电影正式开始...");
System.out.println("Movie(String name, double price, String director) 被调用了。。。。");
this.name = name;
this.price = price;
this.director = director;
}
}
2. 普通代码块与静态代码块
- 使用static修饰的叫做静态代码块
- 没有用static修饰的叫做普通代码块
2.1 静态代码块
-
static代码块也叫静态代码块,作用是对类进行初始化,而且他随着类的加载执行,且只会执行一次,如果是普通代码块,每创建一个对象就会执行一次。
-
类什么时候会被加载??
1) 创建实例对象时(new)
2) 创建子类对象实例,父类也会被加载
3) 使用类的静态成员(静态属性,静态方法)注意:
- 在加载一个类的时候,会先加载与该类有继承关系的父类(从最上层开始加载),如:在加载子类时会先加载父类,在先加载父类时会先加载爷爷类,以此类推。
- 在一个类被加载时,该类的静态代码块一定会执行。
- static代码块在类加载时被执行,且只会执行一次。
-
普通代码块:只有在创建对象实例(构造器被执行)时,会被隐式调用,被创建一次就调用一次。
类被加载的案例:
package 进阶.面向对象01.同步代码块;
import jdk.swing.interop.SwingInterOpUtils;
public class CodeBlock02 {
public static void main(String[] args) {
//类被加载的情况举例
//1. 当创建一个类的实例对象时,类被加载
// AA aa = new AA();
//2. 创建子类对象实例,父类会被加载,而且父类会被先加载,子类被后加载
// AA aa2 = new AA();
// 3. 使用类的静态成员时(静态属性,静态方法)类被加载
// System.out.println(Cat.n1);
//static在类加载时被执行,且只执行一次
Cat cat1 = new Cat();
Cat cat2 = new Cat();
}
}
class BB{
static {
System.out.println("BB的静态代码块执行了......");
}
}
class AA extends BB{
static {
System.out.println("AA的静态代码块执行了......");
}
}
class Cat{
public static int n1 = 999; //静态属性
static {
System.out.println("Cat的静态代码块执行了......");
}
}
总结:
1. static代码块时是在类加载时执行,且只会执行一次。
2. 普通代码块实在创建对象时调用的(构造器执行),且每创建一个对象,执行一次。
2.2 创建一个对象时,类中代码的调用顺序。
- 先 调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按照他们定义的顺序调用)
- 后 调用普通代码块和普通属性初始化(注意:普通代码块和普通属性初始化的调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义顺序调用)
- 最后 调用构造器
实例:
package 进阶.面向对象01.同步代码块;
public class CodeBlock03 {
public static void main(String[] args) {
A a = new A();
}
}
class A{
{
System.out.println("A 普通代码块执行了");
}
private int n2 = getN2();
private static int n1 = getN1();
public A(){
System.out.println("空参构造被执行了");
}
static {
System.out.println("A 静态代码块");
}
private static int getN1() {
System.out.println("getN1被调用了");
return 100;
}
private int getN2() {
System.out.println("getN2被调用了");
return 200;
}
}
2.3 创建一个子类对象时,类中代码的调用顺序。
执行顺序如下
- 父类的静态代码块和静态属性
- 子类的静态代码块和静态属性
- 父类的普通代码块和普通属性初始化
- 父类的构造方法
- 子类的普通代码块和普通属性初始化
- 子类的构造方法
解释说明:假设有两个类A和B,其中A继承了B,创建A类对象。
- 第一步:类加载
- 类加载时,会先加载父类,然后加载子类,故父类的静态代码块和静态属性先执行,然后子类的静态代码块和静态属性执行。
- 第二步:创建对象,注意:重点构造器中默认隐藏两段代码,super和普通代码块的执行。
- 创建对象时,会先去构造器中,由于构造器中隐藏了两个属性,super()和普通代码块,因此,在构造其中会先执行super(),调用super()时会去父类的构造器。
- 在父类的构造其中也同时隐藏了两个属性super()和普通代码块,假设此时父类没有继承其他类,则执行父类的普通代码块,然后执行构造器中内容。
3.父类构造器执行结束后,会执行子类的普通代码块,普通代码块执行完毕后才会执行构造器中内容。
实例:
package 进阶.面向对象01.同步代码块;
public class CodeBlock04 {
public static void main(String[] args) {
A01 a01 = new A01();
}
}
class A02{
private static int n1 = getVal01();
public int m2 = getVal02();
static {
System.out.println("A02 的静态代码块"); // 2
}
{
System.out.println("A02 的一个普通代码块"); //6
}
private static int getVal01() {
System.out.println("A02 getVal01"); // 1
return 10;
}
private int getVal02() {
System.out.println("A02 getVal02"); //5
return 10;
}
public A02(){
//super()
//普通代码块
System.out.println("A02的空参构造方法"); // 7
}
}
class A01 extends A02{
private static int n1 = getVal01();
public int m2 = getVal02();
static {
System.out.println("A01 的静态代码块"); //4
}
{
System.out.println("A01 的一个普通代码块"); //9
}
private static int getVal01() {
System.out.println("A01 getVal01"); //3
return 10;
}
private int getVal02() {
System.out.println("A01 getVal02"); //8
return 10;
}
public A01(){
//super()
//普通代码块
System.out.println("A01 的空参构造方法"); //10
}
}