#新人扶持计划#
今天我们来看下几个易错的static相关的Java面试题。
1、下面这段代码的输出结果是什么?
public class Test extends Base{ static{ System.out.println("test static"); } public Test(){ System.out.println("test constructor"); } public static void main(String[] args) { new Test(); }}class Base{ static{ System.out.println("base static"); } public Base(){ System.out.println("base constructor"); }}
输出结果为:
base statictest staticbase constructortest constructor
这段代码的执行过程:
① 找到main方法入口,main方法是程序入口,但在执行main方法之前,要先加载Test类
② 加载Test类的时候,发现Test类继承Base类,于是先去加载Base类
③ 加载Base类的时候,发现Base类有static块,而是先执行static块,输出base static结果
④ Base类加载完成后,再去加载Test类,发现Test类也有static块,而是执行Test类中的static块,输出test static结果
⑤ Base类和Test类加载完成后,然后执行main方法中的new Test(),调用子类构造器之前会先调用父类构造器
⑥ 调用父类构造器,输出base constructor结果
⑦ 然后再调用子类构造器,输出test constructor结果
2、这段代码的输出结果是什么?
public class Test { Person person = new Person("Test"); static{ System.out.println("test static"); } public Test() { System.out.println("test constructor"); } public static void main(String[] args) { new MyClass(); }}class Person{ static{ System.out.println("person static"); } public Person(String str) { System.out.println("person "+str); }}class MyClass extends Test { Person person = new Person("MyClass"); static{ System.out.println("myclass static"); } public MyClass() { System.out.println("myclass constructor"); }}
输出结果为:
test staticmyclass staticperson staticperson Testtest constructorperson MyClassmyclass constructor
我们来分析下这段代码的执行过程:
① 找到main方法入口,main方法是程序入口,但在执行main方法之前,要先加载Test类
② 加载Test类的时候,发现Test类有static块,而是先执行static块,输出test static结果
③ 然后执行new MyClass(),执行此代码之前,先加载MyClass类,发现MyClass类继承Test类,而是要先加载Test类,Test类之前已加载
④ 加载MyClass类,发现MyClass类有static块,而是先执行static块,输出myclass static结果
⑤ 然后调用MyClass类的构造器生成对象,在生成对象前,需要先初始化父类Test的成员变量,而是执行Person person = new Person(“Test”)代码,发现Person类没有加载
⑥ 加载Person类,发现Person类有static块,而是先执行static块,输出person static结果
⑦ 接着执行Person构造器,输出person Test结果
⑧ 然后调用父类Test构造器,输出test constructor结果,这样就完成了父类Test的初始化了
⑨ 再初始化MyClass类成员变量,执行Person构造器,输出person MyClass结果
⑩ 最后调用MyClass类构造器,输出myclass constructor结果,这样就完成了MyClass类的初始化了
3、这段代码的输出结果是什么?
public class Test { static{ System.out.println("test static 1"); } public static void main(String[] args) { } static{ System.out.println("test static 2"); }}
输出结果为:
test static 1test static 2
虽然在main方法中没有任何语句,但是还是会输出。static块可以出现类中的任何地方(只要不是方法内部,记住,任何方法内部都不行),并且执行是按照static块的顺序执行的。
4、这段代码的输出结果是什么?
public class Test {public static void main(String[] args) {new MyClass();}}class SuperClass {// 父类静态构造代码块static {System.out.println("superClass static block");}// 父类构造函数public SuperClass() {System.out.println("SuperClass constructor");}// 父类构造代码块{System.out.println("superClass block");}// 父类静态变量private static SuperStaticVariable staticVariable = new SuperStaticVariable();// 父类实列变量private SuperVariable variable = new SuperVariable();}class SuperStaticVariable {public SuperStaticVariable() {System.out.println("SuperStaticVariable init");}}class SuperVariable {public SuperVariable() {System.out.println("SuperVariable init");}}class MyClass extends SuperClass {// 子类静态变量static {System.out.println("myclass static");}// 子类静态变量private static MyClassStaticVariable staticVariable = new MyClassStaticVariable();// 子类构造函数public MyClass() {System.out.println("myclass constructor");}// 子类构造代码块{System.out.println("myclass block");}// 子类实列变量private MyClassVariable variable = new MyClassVariable();}class MyClassStaticVariable {public MyClassStaticVariable() {System.out.println("MyClassStaticVariable init");}}class MyClassVariable {public MyClassVariable() {System.out.println("MyClassVariable init");}}
输出结果为:
superClass static blockSuperStaticVariable initmyclass staticMyClassStaticVariable initsuperClass blockSuperVariable initSuperClass constructormyclass blockMyClassVariable initmyclass constructor
如果类还没有被加载:
① 先执行父类的静态代码块和静态变量初始化,并且静态代码块和静态变量的执行顺序只跟代码中出现的顺序有关
② 执行子类的静态代码块和静态变量初始化
③ 执行父类的构造块和父类的实例变量初始化,并且代码块和实例变量的执行顺序只跟代码中出现的顺序有关
④ 执行父类的构造函数
⑤ 执行子类的构造块和子类的实例变量初始化
⑥ 执行子类的构造函数
如果类已经被加载:
则静态代码块和静态变量就不用重复执行,再创建类对象时,只执行与实例相关的变量初始化和构造方法。
总结
加载的顺序:父类的static成员变量 -> 子类的static成员变量 -> 父类的成员变量 -> 父类构造 -> 子类成员变量 -> 子类构造
static只会加载一次,所以通俗点讲第一次new的时候,所有的static都先会被全部载入(以后再有new都会忽略),进行默认初始化。在从上往下进行显示初始化。这里静态代码块和静态成员变量没有先后之分,谁在上,谁就先初始化
构造代码块是什么?把所有构造方法中相同的内容抽取出来,定义到构造代码块中,将来在调用构造方法的时候,会去自动调用构造代码块。构造代码快优先于构造方法。
欢迎小伙伴们关注转发点赞,谢谢~~