《2016展讯校招java软开最后一道题》考点:父类子类static{}块、{}块、构造函数的调用顺序

题目是这样的。给出了如下四个类:Person、Son、Daughter及一个测试类。写出运行结果。

具体代码如下

Person类

package com.wrh.zhanxunInterview;

public class Person {
    String mName=null;
    static String sName=null;
    static{
        System.out.println("Person static create "+sName);//只能调用static的变量

    }
    {
        System.out.println("Person block create "+mName);
    }
    public static void staticMethod(){
        System.out.println("Person staticMethod "+sName);//static 函数和块只能调用static声明的变量和函数
    }

    public void method(){
        System.out.println("Person Method "+mName);//但是static变量可以被不是static的函数调用
    }

    public Person(String name){
        sName=name;
        mName=name;
        System.out.println("Person constructor "+name);
    }

}

Son类

package com.wrh.zhanxunInterview;

public class Son extends Person{
    static{
        System.out.println("Son static create "+sName);//只能调用static的变量

    }
    {
        System.out.println("Son block create "+mName);
    }
    public static void staticMethod(){
        System.out.println("Son staticMethod "+sName);//static 函数和块只能调用static声明的变量和函数
    }

    public Son(String name) {
        super(name);
        // TODO Auto-generated constructor stub
        System.out.println("Son constructor "+name);
    }

}

Daughter类

package com.wrh.zhanxunInterview;

public class Daughter extends Person {
    static{
        System.out.println("Daughter static create "+sName);//只能调用static的变量

    }
    {
        System.out.println("Daughter block create "+mName);
    }
    public static void staticMethod(){
        System.out.println("Daughter staticMethod "+sName);//static 函数和块只能调用static声明的变量和函数
    }
    public void method(){
        System.out.println("Daughter Method "+mName);//但是static变量可以被不是static的函数调用
    }
    public Daughter(String name) {
        super(name);
        // TODO Auto-generated constructor stub
        System.out.println("Daughter constructor "+name);
    }

}

测试类

package com.wrh.zhanxunInterview;

public class staticQuestion {

    public static void main(String[] args) {
        Person childA=new Son("childA");
        Person childB=new Daughter("childB");
        childA.staticMethod();
        childA.method();
        childB.staticMethod();
        childB.method();

    }

}

看如上给出的代码的输出??
经过运行代码最后的结果如下:

上图中画上的红色的线和打X的是我在试卷上面写的。打叉的两行我的结果是

Son staticMethod childA
Daughter staticMethod childB

从结果上面来看
1)当执行

Person childA=new Son(“childA”);(或者是Son s=new Son(“childA”);执行结果也是如下)

时的输出结果为:

Person static create null
Son static create null
Person block create null
Person constructor childA
Son block create childA
Son constructor childA

从上面的结果可以看出,当执行这条语句时,在调用构造函数之前,会先调用父类子类的static{}块,紧接着调用父类{}块,然后才会调用父类的构造函数,再然后调用子类的{}块,最后调用子类的构造函数。

2)当执行

Person childB=new Daughter(“childB”);

时的输出结果为:

Daughter static create childA
Person block create null
Person constructor childB
Daughter block create childB
Daughter constructor childB

从结果可以看出父类的static{}并没有再次被调用,其他的顺序与上面一致。

结论1:当有父类中有static{}块、{}块以及子类中也有static{}块、{}块时,当执行

Person p=new Son();

则调用的顺序为:父类static{}块》子类static{}块》父类{}块》父类构造函数》子类{}块》子类构造函数。且父类static{}块只执行一次。

Java中自由块的执行顺序
java中的自由块分为静态的自由块和非静态的自由块,这两种的执行是有区别的:

  非静态自由块的执行时间是:在执行构造函数之前。

  静态自由块的执行时间是:class文件加载时执行。

执行的时间不同,造成的结果是:

  非静态自由块可以多次执行,只要初始化一个对象就会执行,但是静态自由块只会在类装载的时候执行一次,一般用来初始化类的静态变量的值。
  每次初始化一个对象,都会导致一次非静态块的执行。如果涉及到继承关系,则是:首先执行父类的非静态块,然后是父类的构造函数,接着是自己的自由块,最后是自己的构造函数。静态块的执行时机是在class文件装载的时候,由于class文件只会装载一次,因此静态块只会执行一次,后面再使用这个类时,不会再执行静态块中的代码。 

    更细致的分析class装载的过程,其实静态块的执行时机是在class装载后的初始化阶段。如果采用ClassLoader的loadclass来仅仅装载类而不初始化,是不会触发静态块的执行的。采用Class的forname(String)是采用了默认的initialize为true的情况,也就是初始化了。如果使用forname(String name,boolean initialize, ClassLoader loader),设置initialize为false,同样不会执行静态块。

在执行class装载后的初始化阶段包括:运行方法,这个方法中就是类变量的初始化语句和静态自由块语句。这个方法是由java的编译器收集信息后生成的,不能显示的调用。

3)当执行

childA.staticMethod();
和childB.staticMethod();

时都输出

Person staticMethod childB

即调用了父类中的staticMethod的方法,至于为什么是父类的引用但是是子类的对象为什么会调用父类的方法的原因,现在还不能而知??有待研究

发表评论