类加载机制与双亲委派机制
类加载机制
JVM加载一个类共分为3个步骤:加载,链接,初始化。其中链接又分为3个步骤:验证,准备,解析。
这些阶段通常是互相交叉混合式进行的(即可以相互调用),但必须是按这个顺序开始的(解析过程不一定,它可以在初始化之后开始,这是为了支持动态绑定(即多态))。
1. 加载
- 共分为3步:1)获取定义此类的二进制字节流;2)将字节流代表的静态存储结构转化为方法区的运行时数据结构;3)在堆中实例化一个这个类的Class对象,作为方法区这个类的入口
2. 链接
- 验证
主要是确认字节流包含的信息符合虚拟机的要求,不含有害信息危害虚拟机安全,主要有4个阶段:文件格式验证,元数据验证,字节码验证,符号引用验证。 - 准备
为类中的静态变量赋初始值(零值),但如果是静态常量(即被final修饰),在准备阶段直接就它设置为真正的初始值了。 - 解析
将符号引用转为直接引用。
3. 初始化
实际上是执行类构造器 <clinit>() 方法的过程,为静态变量真正赋值的过程。虚拟机保证父类的<clinit>() 优于子类的执行(这也是父类的静态代码块(static {})优于子类静态代码块执行的原因),所以虚拟机中执行第一个<clinit>() 的类永远是Object。
JVM规定了有且只有4种引用方式必须对类与接口初始化,称为主动引用:1)new对象;2)使用反射时;3)初始化一个类时,若其父类还没初始化,先初始化父类(接口不同,只有用到父接口时才初始化);4)JVM启动时,初始化主类(public class)。
类加载器
执行加载阶段的第一步的代码模块,称为“类加载器”。只有在同一类加载器的情况下,比较两个类是否“相等”才有意义,否则即使有两个同名的类(来自同一Class文件),它们也不等。(这里的相等包括equal() 方法,instanceof,isAssignableFrom()方法)。
JVM预定义了3种类加载器:启动类加载器 (BootStrap ClassLoader),扩展类加载器 (Extension ClassLoader),系统类加载器(又叫应用程序加载器) (System ClassLoader)。
- 启动类加载器:用于加载%JAVA_HOME%\lib 下的Java和心累,不允许开发者直接引用。
- 扩展类加载器:用于加载JRE的扩展类,即JRE目录下的 lib\ext,开发者可直接引用。
- 系统类加载器:用于加载CLASSPATH下的类,开发者可直接引用
双亲委派机制
某个类收到了类加载的请求,当前类会把这个请求交给父加载器完成,依次向上递归,直到传到最顶层的启动类加载器;若父加载器可以完成,则成功返回,若不能完成,子加载器才会尝试自己加载。
好处:1)防止类重复加载;2)防止Java核心类库被篡改(如:网络中传来一个java.lang.Object类,通过双亲委派传递到启动类加载器,JVM在Java核心类中发现有java.lang.Object类,则加载这个,而不加载网络传来的java.lang.Object类)。