这里的原理和例子来源自尚硅谷的讲师宋红康(深入理解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类,输出的结果为 这是为什么呢,主方法里面并没有调用任何函数?这就需要讲解一下类的初始化过程了。 类的初始化过程 所以当运行主方法时,将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()方法 *根据这个分析可以得出结果。