代码块分为静态代码块和非静态代码块,他们和构造函数的执行顺序在面试中经常考察,理解了下面这些基本知识,就很容易做出来,开发固然重要,但是基础也要经常回顾。
一个类的源文件(.java)被编译为字节码文件(.class)后,当需要使用某个类时,Java 虚拟机就将该类的字节码文件读入内存,加载类中的信息,静态代码块只被执行一次,且静态代码块不能被访问修饰符(private、default、protected、public)修饰。静态代码块是初始化该类的,而构造函数才是初始化该类具体的对象实例的。
// 静态代码块 static { ... }
1、显式使用 Class.forName() 加载某个类时。
2、执行一个类的 main() 方法时。
3、使用构造函数创建(new)一个对象时,如 Test test = new Test(),等同于 Test test = Class.forName().newInstance()。
4、调用类的静态变量(static)时,注意调用静态常量(final static 关键字修饰)是不会执行静态代码块的。
5、调用类的静态函数时,无论是否有 final 关键字修饰,都会执行静态代码块。
1、多个静态代码块按定义的顺序从前往后依次执行。
2、使用 Class.forName() 时不初始化该类不会执行静态代码块,如 Class.forName(“Test”, false, Test.class.getClassLoader())。
静态代码块具有初始化静态成员变量和给静态成员变量赋值的作用,如单例模式中的饿汉模式,类一旦加载就实例化出一个对象,用到的就是静态代码块。
非静态代码块又称为初始化块,直接用 {} 定义,可以用在类中和方法中。
// 非静态代码块 { ... }
静态代码块执行之后,构造函数执行之前,每一次创建对象时执行。
注意:多个非静态代码块按定义的顺序从前往后依次执行。
非静态代码块也有初始化变量和对象的作用,但这个初始化有些鸡肋,因为我们都是在构造函数中初始化对象的。
一个类中,按照如下顺序执行:
1、执行静态代码块
2、执行非静态代码块
3、执行构造函数
对于静态变量、静态代码块、变量、非静态代码块、构造函数,它们的初始化顺序依次是(静态变量、静态初始化块)>(变量、非静态代码块)> 构造函数。
在多个类的继承中,按照如下顺序执行:
1、执行父类的静态代码块,初始化父类静态变量。
2、执行子类的静态代码块,初始化子类静态变量。
3、执行父类的非静态代码块和父类的构造函数,初始化父类的成员变量。
3、执行子类的非静态代码块和字类的构造函数,初始化子类的成员变量。
在继承中,创建一个子类对象时,会先加载父类文件,执行父类的静态代码块,然后执行子类的静态代码块,再然后才是初始化对象,执行父类的非静态代码块、父类的构造函数,最后执行子类的非静态代码块、子类的构造函数。