这里的原理和例子来源自尚硅谷的讲师宋红康(深入理解JVM)和柴林燕(Java面试题),表示非常感谢。
java程序将字节码通过类的加载子系统将类的元信息加载到方法区中,一共有三步,加载,链接,初始化。具体请看深入理解JVM。这里通过题目演示类的初始化和实例初始化。
father类
public class Father{
private int i = test();
private static int j = method();
static{
System.out.print("(1)");
}
Father(){
System.out.print("(2)");
}
{
System.out.print("(3)");
}
public int test(){
System.out.print("(4)");
return 1;
}
public static int method(){
System.out.print("(5)");
return 1;
}
}
son类
public class Son extends Father{
private int i = test();
private static int j = method();
static{
System.out.print("(6)");
}
Son(){
// super();//写或不写都在,在子类构造器中一定会调用父类的构造器
System.out.print("(7)");
}
{
System.out.print("(8)");
}
public int test(){
System.out.print("(9)");
return 1;
}
public static int method(){
System.out.print("(10)");
return 1;
}
public static void main(String[] args) {
}
}
若运行son类,输出的结果为
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyIDOzMTNwADMxAzNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
这是为什么呢,主方法里面并没有调用任何函数?这就需要讲解一下类的初始化过程了。
类的初始化过程
所以当运行主方法时,将son和father类加载进虚拟机的方法区。main方法在son类中,要加载son类的时候需要先加载其父类father,而在初始化son的时候需要先初始化father,在初始化father时,执行方法,赋值静态的类变量的静态代码块。所以就先输出(5)(1),接下里初始化son类,也是赋值静态的类变量的静态代码块。所以输出(10)(6)。
实例的初始化过程
在上面代码的基础上,修改main方法,加上一下三行代码
Son s1 = new Son();
System.out.println();
Son s2 = new Son();
则输出结果为
其中(5)(1)(10)(6)上面为两个类初始化的输出结果,主要讨论后面的输出结果,这就涉及到实例的初始化和方法的重写了。
分析结果:我们从上知道,实例化对象就是调用方法,也就是构造器,**注意:每个构造器不管你加不加都默认有一句super();**也即是说先需要调用父类的构造器。然后在初始化非静态变量和非静态代码块,最后再执行构造器。所以过程如下
son类
* 子类的实例化方法<init>:
* (1)super()(最前) (9)(3)(2)
* (2)i = test(); (9)
* (3)子类的非静态代码块 (8)
* (4)子类的无参构造(最后) (7)
father类
* 父类的实例化方法:
* (1)super()(最前)
* (2)i = test();
* (3)父类的非静态代码块
* (4)父类的无参构造(最后)
*
* 非静态方法前面其实有一个默认的对象this
* this在构造器(或<init>)它表示的是正在创建的对象,因为这里是在创建Son对象,所以
* test()执行的是子类重写的代码(面向对象多态)
*
* 这里i=test()执行的是子类重写的test()方法
*
根据这个分析可以得出结果。