背景知识了解: 一个类加载离不开Jvm,Jvm是什么?Java Virtual Machine(Java虚拟机)的缩写。Jvm执行字节码(.class文件)时,将其翻译成各个平台都能运行的机器指令。因此,Java能一次编译,到处运行(各个平台)。
运行一个java程序,即可启动一个jvm进程。同一个jvm进程里的所有线程,变量共享。不同的Jvm进程 是独立的,一个Jvm运行结束后,该程序里运行的变量在内存不占空间了。因此他们互相不干涉。
进入主题: 在一个Jvm想用一个类到把这个类加载进入内存这个过程中发生什么事情呢?
经过三步骤: 1. 类加载 2.类连接 3.类初始化
首先,类加载就是把Class文件放入内存里,创建一个Class对象。Ps:要使用类,就必须有“对象”。(所以提交代码时候,.java文件没提交没关系,只要.class文件提交了就万事不怕啦)
接着,类连接,在干三件事。检查语法是不是有问题,和其他类是不是协调。给静态成员赋一个初始值。最后就是解析,将符号引用改成直接引用。(最后一步,开始不太理解,可参考例子:int a = 1;解析就是把a直接改成1 )
最后,类初始化主要对类变量进行初始化。以下两步:1、声明类变量并指定初始值 2、静态初始化块时给类变量一个初始值。(先直接父类,间接父类,再自己类初始化)
类啥时候初始化呢?
举例:
创建类的实例。
调用类方法。
访问类变量或为静态变量赋值。
反射的方法强行创建类或者接口对应的java.lang.Class对象。
初始化某父类的子类。(父类会被先初始化)
java.exe直接运行某主类。先初始化该主类。
小注意:程序访问静态变量也可能不会初始化类(“宏变量”使用:final初始化 类变量值,该值编译时就能确定)
package Test01; class Test{ static{ System.out.println("静态初始化块......."); } final static int i=0; } public class CompileConstantTest { public static void main(String[] args) { System.out.println(Test.i); } }
看结果发现类并没执行初始化块,所以类没初始化。
理解 Jvm借助类加载器这个工具把.class文件加载进内存。
类加载器
根加载器:加载系统核心类,。不是java.lang.ClassLoader的子类。
扩展加载器 %JAVA_HOME%/jre/lib/ext(我的机子是 D:\jdk\jre\lib\ext)在该目录下把自己写的类打包进去,可扩展核心类以外的新功能。(系统类加载器的父加载器)
系统类加载器:静态方法getSystemClassLoader(),最常用。加载来自CLASSPATH环境变量的类及jar包,java命令的-classpath属性和java.class.path系统属性(这就是为什么运行Java要配置path,classpath环境变量的原因了,配置详细可见 http://www.cnblogs.com/Fskjb/archive/2011/01/06/1927581.html)
下图来自 http://www.cnblogs.com/wangrongchen/p/9242789.html