面试题:类初始化和实例初始化
题目
public class Father {
private int i = test();
private static int j = method();
static{
System.out.println("(1)");
}
Father() {
System.out.println("(2)");
}
{
System.out.println("(3)");
}
public int test(){
System.out.println("(4)");
return 1;
}
public static int method() {
System.out.println("(5)");
return 1;
}
}
public class Son extends Father {
private int i = test();
private static int j = method();
static {
System.out.println("(6)");
}
Son() {
super();
System.out.println("(7)");
}
{
System.out.println("(8)");
}
public int test(){
System.out.println("(9)");
return 1;
}
public static int method() {
System.out.println("(10)");
return 1;
}
public static void main(String[] args) {
Son son = new Son();
System.out.println();
Son son1 = new Son();
}
}
看这么两段代码,回答最后的输出结果。
类初始化过程
- 一个类要创建实例需要先加载并初始化该类。
- main方法所在的类需要先加载和初始化。
- 一个子类要初始化需要先初始化父类。
- 一个类初始化就是执行()方法。
- ()方法由静态类变量显示赋值代码和静态代码块组成。
- 类变量显示赋值代码和静态代码块代码从上到下顺序执行。
- ()方法只执行一次。
实例初始化过程
- 实例初始化就是执行()方法。
- ()方法可能重载有多个,有几个构造器就有几个()方法。
- ()方法由非静态实例变量显示赋值代码和非静态代码块、对应构造器代码组成。
- 非静态实例变量显示赋值代码和非静态代码块代码从上到下顺序执行,而对应构造器的代码最后执行。
- 每次创建实例对象,调用对应构造器,执行的就是对应的方法。
- 方法的首行是super()或者super(实参列表),super方法写或不写都是存在的,及对应父类的方法
方法的重写Override
哪些方法不可以被重写
- final方法
- 静态方法
- private等子类中不可见方法
对象的多态性
- 子类如果重写了父类的方法,通过子类对象调用的一定是子类重写过的代码
- 非静态方法默认的调用对象是this
- this对象在构造器或者说方法中就是正在创建的对象
答案解析
- 首先是类的初始化,先要初始化main方法所在的类,即Son类,因为Son继承了Father类,所以要先初始化Father类
- Father类的初始化是从静态变量和静态代码块顺序执行,也就是先打印5,再打印1
- Son类的初始化逻辑相同,先打印10,再打印6
- 然后是实例的初始化,同样Son继承了Father,那么需要先初始化Father的实例
- father实例的初始化顺序应该是9,3(Son类重写了test方法)、2,变量赋值和非静态代码块顺序执行,构造方法最后执行。
- son实例的初始化顺序为9、8、7
- 第二个son实例的初始化同第二步
所以最后的答案为:5、1、10、6、9、3、2、9、8、7
9、3、2、9、8、7