写点什么

一道有意思的“初始化”面试题

  • 2022 年 5 月 12 日
  • 本文字数:2529 字

    阅读完需:约 8 分钟

System.out.println("Cupboard 构造方法");


}


void otherMethod(int marker) {


System.out.println("otherMethod(" + marker + ")");


}


static Bowl bowl5 = new Bowl(5);


}


public class StaticInitialization {


public static void main(String args[]) {


System.out.println("main()");


cupboard.otherMethod(1);


}


static Table table = new Table();


static Cupboard cupboard = new Cupboard();


}


涉及的知识点:


=======


  1. 在类的内部,变量定义的先后顺序决定了初始化顺序。即使变量定义散布于方法定义之间,它们仍旧会在任何方法(包括构造方法)被调用之前得到初始化。

  2. 无论创建多少个对象,静态数据都只占用一份存储区域。static 关键字不能应用于局部变量,因此它只能作用于域。如果一个域是静态的基本类型域,且也没有对它进行初始化,那么它就会获得基本类型的标准初值;如果它是一个对象引用,那么它的默认初始化值就是 null。

  3. 静态初始化只有在必要时刻才进行,例如:类里面的静态变量,只有当类被调用时才会初始化(执行),并且静态变量不会再次被初始化(执行),即静态变量只会初始化(执行)一次。?

  4. 初始化的顺序是先静态对象,然后是非静态对象。

  5. 当有父类时,完整的初始化顺序为:父类静态变量(静态代码块)->子类静态变量(静态代码块)->父类非静态变量(非静态代码块)->父类构造器 ->子类非静态变量(非静态代码块)->子类构造器 。

  6. 即使没有显示的使用 static 关键字,构造器实际上也是静态方法。


下面是上面第 5 点提到的一些关键字的例子:


**静态变量(类变量):**static 修饰的变量。


static Bowl bowl7 = new Bowl(7);


静态代码块**:**static 修饰的代码块,可以放多个语句。看起来像个方法,实际上只是一段跟在 static 关键字后面的代码。


static {


System.out.println("静态代码块");


}


**非静态变量(实例变量):**普通变量,没有 static 修饰。


Bowl bowl6 = new Bowl(6);


**非静态代码块:**普通代码块,没有 static 修饰,可以放多个语句。


{


System.out.println("非静态代码块");


}


**构造方法(构造器):**跟类同名的方法,可以有多个,如果没有写构造方法,则会自动创建一个为空的构造器。


Tableware() {


System.out.println("构造方法");


}


看完这几个知识点,你能写出正确答案了吗,请自己动手试一试。


题目详解:


=====


  1. 首先我们找到“public?class”,此时我们看到熟悉的 main()方法,但是在 main()方法之外有两行 static 的变量定义,根据上面的知识点 1 可知,变量的初始化会在任何方法之前,因此,先执行第 49 行代码的 Table 初始化。注意:如果此处 Table 的定义不是“static”修饰,则不会执行,因为在执行 main()方法时,可以理解为执行了代码“StaticInitialization.main(null)”,要执行 main()方法必须加载 StaticInitialization 类,所以静态域(table 和 cupboard)会得到初始化,而非静态域只有创建类的实例时才会得到初始化,例如执行了代码“StaticInitialization s = new StaticInitialization()”。

  2. 此时,我们来看 Table 类,发现 Table 有父类 Tableware,根据上面的知识点 5,可知会先初始化“父类静态变量(静态代码块)”,即第 7、9 行代码;接着是“子类静态变量(静态代码块)”,即第 24、26、31 行代码;接着执行“父类非静态变量(非静态代码块)”,即第 14 行代码;接着执行“父类构造器”,即第 12 行代码;接着执行“子类非静态变量(非静态代码块)”,即第 18、20、22 行代码;最后执行“子类构造器?”,即第 29 行代码;至此,第 49 行代码,table 的初始化结束。

  3. 接着,执行第 50 行代码 Cupboard 的初始化,过程跟 Table 类似。我们发现 Cupboard 也有父类,并且跟之前的 Table 一样是 Tableware,此时我们要注意上面的知识点 2/3,“静态变量只会初始化(执行)一次”,因此 Tableware 中的静态变量在此次 Cupboard 的初始化中不会再初始化。根据上面的知识点 5,首先执行“父类静态变量(静态代码块)”,已经执行过,跳过;接着执行“子类静态变量(静态代码块)”,即第 35、42 行代码;接着执行“父类非静态变量(非静态代码块)”,即第 14 行代码;接着执行“父类构造器”,即第 12 行代码;接着执行“子类非静态变量(非静态代码块)”,即第 34 行代码;最后执行“子类构造器?”,即第 37 行代码;至此,第 50 行代码,cupboard 的初始化结束。

  4. 两个静态变量初始化完成后,接着执行 main()方法,首先执行第 46 行代码,输出“main()”,接着执行 47 行代码,即第 40 行代码。至此,整个过程全部执行完毕。


答案:


===


下面是标注了执行顺序的代码。


class Bowl {


Bowl(int marker) {


System.out.println("Bowl(" + marker + ")");


}


}


class Tableware {


static Bowl bowl7 = new Bowl 《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 (7); // 1


static {


System.out.println("Tableware 静态代码块"); // 2


}


Tableware() {


System.out.println("Tableware 构造方法"); // 7、15


}


Bowl bowl6 = new Bowl(6); // 6、14


}


class Table extends Tableware {


{


System.out.println("Table 非静态代码块_1"); // 8


}


Bowl bowl5 = new Bowl(5); // 9


{


System.out.println("Table 非静态代码块_2"); // 10


}


static Bowl bowl1 = new Bowl(1); // 3


static {


System.out.println("Table 静态代码块"); // 4


}


Table() {


System.out.println("Table 构造方法"); // 11


}


static Bowl bowl2 = new Bowl(2); // 5


}


class Cupboard extends Tableware {


Bowl bowl3 = new Bowl(3); // 16


static Bowl bowl4 = new Bowl(4); // 12


Cupboard() {


System.out.println("Cupboard 构造方法"); // 17


}


void otherMethod(int marker) {


System.out.println("otherMethod(" + marker + ")"); // 19


}


static Bowl bowl5 = new Bowl(5); // 13


}


public class StaticInitialization {


public static void main(String args[]) { // 第三执行


System.out.println("main()"); // 18


cupboard.otherMethod(1);


}


static Table table = new Table(); // 第一执行


static Cupboard cupboard = new Cupboard(); // 第二执行


}


最后输出:


=====


Bowl(7)


Tableware 静态代码块


Bowl(1)


Table 静态代码块


Bowl(2)


Bowl(6)


Tableware 构造方法


Table 非静态代码块_1

用户头像

还未添加个人签名 2022.04.13 加入

还未添加个人简介

评论

发布
暂无评论
一道有意思的“初始化”面试题_Java_爱好编程进阶_InfoQ写作社区