目录
1.编译 写好:”.java”代码后,会通过编译器将代码编译成.class后缀的字节码文件
Java是平台无关的,实现语言无关性的基础就是虚拟机和字节码存储格式
只要编译器按照虚拟机规范,编译成对应的class文件,这个class文件就能够被JVM加载,不同的操作系统通过运行对应版本JVM来载入这个class文件运行,则实现了平台无关性。
2.类加载 JVM要运行这些.class字节码文件中的代码,那就要把".class"文件中包含的各种类给加载进来?此时就涉及到类加载的过程
通过类加载器,可以把编译好的那些class字节码文件给加载到JVM中
3.链接
在类被加载后,需要通过链接过程将它合并到JVM的运行状态中,然后才开始使用,链接包括三个步骤: 验证 假如class文件被人篡改了,里面的字节码不符合虚拟机的规范,那么JVM是没法去执行这个字节码的
所以在类加载到之后,真正使用前,一定要先对其验证下,校验它一定要完全符合JVM规范,后续才能交给JVM来运行
准备 准备过程中,会为类分配内存空间,给内部的类变量分配内存空间并设置默认的初始值
准备过程并不会执行代码
解析 确保这些被引用的类能被正确的找到,这个过程可能会导致其他的Java类被加载。
4.初始化(链接完成之后执行)
初始化过程的主要操作是执行静态代码块和初始化静态变量,按照源代码中从上到下的顺序一次执行 一个类被初始化之前,它的直接父类也需要被初始化
一个接口的初始化,不会引起其父接口的初始化
二、类初始化和实例初始化面试题
以下程序,输出的结果是
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; }}
public class Son extends Father{ private int i = test(); private static int j = method(); static { System.out.print("(6)"); } Son(){ 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) { System.out.println("......\n创建第一个对象......"); Son s1 = new Son(); System.out.println("......\n创建第二个对象......"); Son s2 = new Son(); }}
结果分析
整个过程包括了类初始化过程和实例初始化过程
1.类初始化过程 一个类要创建实例需要先加载并初始化该类,main方法所在的类需要先加载和初始化
一个子类要初始化需要先初始化父类
一个类初始化就是执行方法,由虚拟机帮我们创建 cl:类初始化的过程 ()方法由静态变量显示赋值代码和静态代码块组成
类变量显示赋值代码和静态代码块代码从上到下顺序执行
()方法只执行一次
先初始化父类:打印(5)(1)
private static int j = method();static{ System.out.println(“(1)”);}
子类初始化: 打印(10)(6)
private static int j = method();static{ System.out.println(“(6)”);}
2.子类的实例初始化就是执行方法 ()方法可能重载有多个,有几个构造器就有几个方法
()方法由非静态实例变量显示赋值代码和非静态代码块、对应构造器代码组成
非静态实例变量显示赋值代码和非静态代码块代码从上到下顺序执行,而对应构造器的代码最后执行
每次创建实例对象,调用对应构造器,执行的就是对应的方法
方法的首行是super()或super(实参列表),即对应父类的方法
非静态方法前面其实有一个默认的对象this
this在构造器(或)它表示的是正在创建的对象,因为这里创建的是Son对象,所以test()执行的是子类重写的代码(面向对象多态)
Father中:private int i = test();执行的是子类的方法打印(9)
再执行
{
System.out.println(“(3)”);打印(3)
}
再执行构造函数中 打印(2)
Son中类似分析打印:(9) (8) (7)
3.创建第二个Son对象 上述实例化方法又会被执行一次
打印(9)(3)(2)(9)(8)(7)