前言:想要彻底弄明白此类题目,需要把各种代码块的区别和类的加载顺序搞明白。只要这些真正明白了,那题目再怎么变动也都不过如此。
一、代码块
1、构造代码块(动态代码块)
构造代码块也叫动态代码块,位于非静态成员变量和构造方法之间,一般用于初始化成员变量。一定要注意的是:初始化当前类的所有类对象时,只要调用构造方法,就一定会执行对应的构造代码块!!!
2、静态代码块
静态代码块位于静态成员变量之后,一般用于初始化程序,只会在类的加载时执行一遍。只要类文件加载,静态代码块中所有内容全部执行。
3、局部代码块
局部代码块是位于特定方法或特定结构内部的用一对大括号括起来的代码块。一般用于限定当前变量的声明周期,能够提高效率,解决内存,让JVM回收内存的效率提升。
二、类的加载顺序
废话不多说,直接上代码:
class Father {
static {
System.out.println("父类静态代码块");
}
{
System.out.println("父类构造代码块");
}
public Father() {
System.out.println("父类构造方法");
}
}
class Son extends Father {
static {
System.out.println("子类静态代码块");
}
{
System.out.println("子类构造代码块");
}
public Son() {
System.out.println("子类构造方法");
}
}
public class Test {
public static void main(String[] args) {
Son son = new Son();
}
}
运行结果:
从运行结果中就可以非常清楚地看到类的加载的具体顺序。
三、相关练习题
public class BlockTest {
static BlockTest b1 = new BlockTest();
static BlockTest b2 = new BlockTest();
static {
System.out.println("静态代码块");
}
{
System.out.println("构造代码块");
}
public BlockTest() {
System.out.println("构造方法");
}
public static void main(String[] args) {
new BlockTest();
}
}
运行结果:
程序运行首先会加载BlockTest类,加载类首先会给所有静态成员变量分配内存空间,紧接着给静态成员变量初始化。此处初始化的内容是new BlockTest(),但是此时两个静态成员变量已经分配好了内存,之后不会再进行创建。所以就会调用BlockTest类的构造方法,然而执行构造方法前一定会先执行构造代码块!给两个静态成员变量初始化完成后,会执行静态代码块。静态代码块执行完毕后就会开始main方法的执行,再次执行new BlockTest(),所以再次执行了构造代码块和构造方法。
如果将题目稍作改动,将两个静态成员变量改为非静态成员变量。
public class BlockTest {
BlockTest b1 = new BlockTest();
BlockTest b2 = new BlockTest();
static {
System.out.println("静态代码块");
}
{
System.out.println("构造代码块");
}
public BlockTest() {
System.out.println("构造方法");
}
public static void main(String[] args) {
new BlockTest();
}
}
此时的运行结果将是无穷无尽的,直到内存爆炸。原因在于非静态成员变量在每次实例化对象时都会进行创建,一直反复创建下去。
本文都是个人理解,如有什么不对的地方,还望指出~