Java虚拟机类载入过程是把Class类文件载入到内存。并对Class文件里的数据进行校验、转换解析和初始化,终于形成能够被虚拟机直接使用的java类型的过程。

在载入阶段,java虚拟机须要完毕下面3件事:

a.通过一个类的全限定名来获取定义此类的二进制字节流。

b.将定义类的二进制字节流所代表的静态存储结构转换为方法区的执行时数据结构。

c.在java堆中生成一个代表该类的java.lang.Class对象,作为方法区数据的訪问入口。

Java虚拟机的类载入是通过类载入器实现的, Java中的类载入器体系结构例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center">

(1).BootStrap ClassLoader:启动类载入器。负责载入存放在%JAVA_HOME%\lib文件夹中的,或者通被-Xbootclasspath參数所指定的路径中的。而且被java虚拟机识别的(仅依照文件名称识别。如rt.jar,名字不符合的类库,即使放在指定路径中也不会被载入)类库到虚拟机的内存中,启动类载入器无法被java程序直接引用。

(2).Extension ClassLoader:扩展类载入器,由sun.misc.Launcher$ExtClassLoader实现,负责载入%JAVA_HOME%\lib\ext文件夹中的。或者被java.ext.dirs系统变量所指定的路径中的全部类库,开发人员能够直接使用扩展类载入器。

(3).Application ClassLoader:应用程序类载入器,由sun.misc.Launcher$AppClassLoader实现。负责载入用户类路径classpath上所指定的类库。是类载入器ClassLoader中的getSystemClassLoader()方法的返回值,开发人员能够直接使用应用程序类载入器,假设程序中没有自己定义过类载入器,该载入器就是程序中默认的类载入器。

注意:上述三个JDK提供的类载入器尽管是父子类载入器关系,可是没有使用继承,而是使用了组合关系。

从JDK1.2開始。java虚拟机规范推荐开发人员使用双亲委派模式(ParentsDelegation Model)进行类载入,其载入步骤例如以下:

(1).假设一个类载入器收到了类载入请求,它首先不会自己去尝试载入这个类,而是把类载入请求委派给父类载入器去完毕。

(2).每一层的类载入器都把类载入请求委派给父类载入器,直到全部的类载入请求都应该传递给顶层的启动类载入器。

(3).假设顶层的启动类载入器无法完毕载入请求,子类载入器尝试去载入,假设连最初发起类载入请求的类载入器也无法完毕载入请求时,将会抛出ClassNotFoundException。而不再调用其子类载入器去进行类载入。

双亲委派 模式的类载入机制的长处是java类它的类载入器一起具备了一种带优先级的层次关系。越是基础的类。越是被上层的类载入器进行载入,保证了java程序的稳定执行。双亲委派模式的实现:

  1. protected synchronized Class<?

    > loadClass(String name, Boolean resolve) throws ClassNotFoundException{

  2. //首先检查请求的类是否已经被载入过
  3. Class c = findLoadedClass(name);
  4. if(c == null){
  5. try{
  6. if(parent != null){//委派父类载入器载入
  7. c = parent.loadClass(name, false);
  8. }
  9. else{//委派启动类载入器载入
  10. c = findBootstrapClassOrNull(name);
  11. }
  12. }catch(ClassNotFoundException e){
  13. //父类载入器无法完毕类载入请求
  14. }
  15. if(c == null){//本身类载入器进行类载入
  16. c = findClass(name);
  17. }
  18. }
  19. if(resolve){
  20. resolveClass(c);
  21. }
  22. return c;
  23. }
protected synchronized Class<?

> loadClass(String name, Boolean resolve) throws ClassNotFoundException{
//首先检查请求的类是否已经被载入过
Class c = findLoadedClass(name);
if(c == null){
try{
if(parent != null){//委派父类载入器载入
c = parent.loadClass(name, false);
}
else{//委派启动类载入器载入
c = findBootstrapClassOrNull(name);
}
}catch(ClassNotFoundException e){
//父类载入器无法完毕类载入请求
}
if(c == null){//本身类载入器进行类载入
c = findClass(name);
}
}
if(resolve){
resolveClass(c);
}
return c;
}

若要实现自己定义类载入器,仅仅须要继承java.lang.ClassLoader 类。而且重写其findClass()方法就可以。java.lang.ClassLoader 类的基本职责就是依据一个指定的类的名称,找到或者生成其相应的字节代码,然后从这些字节代码中定义出一个 Java 类,即 java.lang.Class 类的一个实例。除此之外,ClassLoader 还负责载入 Java 应用所需的资源,如图像文件和配置文件等。ClassLoader中与载入类相关的方法例如以下:

方法

说明

getParent()

返回该类载入器的父类载入器。

loadClass(String name)

载入名称为 二进制名称为name 的类。返回的结果是 java.lang.Class 类的实例。

findClass(String name)

查找名称为 name 的类,返回的结果是 java.lang.Class 类的实例。

findLoadedClass(String name)

查找名称为 name 的已经被载入过的类。返回的结果是 java.lang.Class 类的实例。

resolveClass(Class<?> c)

链接指定的 Java 类。

注意:在JDK1.2之前。类载入尚未引入双亲委派模式,因此实现自己定义类载入器时经常重写loadClass方法,提供双亲委派逻辑。从JDK1.2之后,双亲委派模式已经被引入到类载入体系中。自己定义类载入器时不须要在自己写双亲委派的逻辑,因此不鼓舞重写loadClass方法,而推荐重写findClass方法。

在Java中。随意一个类都须要由载入它的类载入器和这个类本身一同确定其在java虚拟机中的唯一性,即比較两个类是否相等。仅仅有在这两个类是由同一个类载入器载入的前提之下才有意义,否则,即使这两个类来源于同一个Class类文件,仅仅要载入它的类载入器不同样,那么这两个类必然不相等(这里的相等包含代表类的Class对象的equals()方法、isAssignableFrom()方法、isInstance()方法和instanceofkeyword的结果)。

样例代码例如以下:

  1. package com.test;
  2. public class ClassLoaderTest {
  3. public static void main(String[] args)throws Exception{
  4. //匿名内部类实现自己定义类载入器
  5. ClassLoader myClassLoader = new ClassLoader(){
  6. protected Class<?> findClass(String name)throws ClassNotFoundException{
  7. //获取类文件名称
  8. String filename = name.substring(name.lastIndexOf(“.”) + 1) + “.class”;
  9. InputStream in = getClass().getResourceAsStream(filename);
  10. if(in == null){
  11. throw RuntimeException(“Could not found class file:” + filename);
  12. }
  13. byte[] b = new byte[in.available()];
  14. return defineClass(name, b, 0, b.length);
  15. }catch(IOException e){
  16. throw new ClassNotFoundException(name);
  17. }
  18. };
  19. Object obj = myClassLoader.loadClass(“com.test.ClassLoaderTest”).newInstance();
  20. System.out.println(obj.getClass());
  21. System.out.println(obj instanceof com.test. ClassLoaderTest);
  22. }
  23. }
package com.test;

public class ClassLoaderTest {
public static void main(String[] args)throws Exception{
//匿名内部类实现自己定义类载入器
ClassLoader myClassLoader = new ClassLoader(){
protected Class<? > findClass(String name)throws ClassNotFoundException{
//获取类文件名称
String filename = name.substring(name.lastIndexOf(“.”) + 1) + “.class”;
InputStream in = getClass().getResourceAsStream(filename);
if(in == null){
throw RuntimeException(“Could not found class file:” + filename);
}
byte[] b = new byte[in.available()];
return defineClass(name, b, 0, b.length);
}catch(IOException e){
throw new ClassNotFoundException(name);
}
};
Object obj = myClassLoader.loadClass(“com.test.ClassLoaderTest”).newInstance();
System.out.println(obj.getClass());
System.out.println(obj instanceof com.test. ClassLoaderTest);
}
}

输出结果例如以下:

com.test.ClassLoaderTest

false

之所以instanceof会返回false。是由于com.test.ClassLoaderTest类默认使用Application ClassLoader载入,而obj是通过自己定义类载入器载入的。类载入不同样,因此不相等。

类载入器双亲委派模型是从JDK1.2以后引入的。而且仅仅是一种推荐的模型。不是强制要求的,因此有一些没有遵循双亲委派模型的特例:

(1).在JDK1.2之前,自己定义类载入器都要覆盖loadClass方法去实现载入类的功能,JDK1.2引入双亲委派模型之后,loadClass方法用于委派父类载入器进行类载入。仅仅有父类载入器无法完毕类载入请求时才调用自己的findClass方法进行类载入,因此在JDK1.2之前的类载入的loadClass方法没有遵循双亲委派模型。因此在JDK1.2之后。自己定义类载入器不推荐覆盖loadClass方法。而仅仅须要覆盖findClass方法就可以。

(2).双亲委派模式非常好地攻克了各个类载入器的基础类统一问题,越基础的类由越上层的类载入器进行载入,可是这个基础类统一有一个不足,当基础类想要调用回下层的用户代码时无法委派子类载入器进行类载入。为了解决问题JDK引入了ThreadContext线程上下文,通过线程上下文的setContextClassLoader方法能够设置线程上下文类载入器。

JavaEE仅仅是一个规范,sun公司仅仅给出了接口规范,详细的实现由各个厂商进行实现,因此JNDI。JDBC,JAXB等这些第三方的实现库就能够被JDK的类库所调用。

线程上下文类载入器也没有遵循双亲委派模型。

(3).近年来的热码替换,模块热部署等应用要求不用重新启动java虚拟机就能够实现代码模块的即插即用。催生了OSGi技术。在OSGi中类载入器体系被发展为网状结构。OSGi也没有全然遵循双亲委派模型。

Java虚拟机的类载入机制的更多相关文章

  1. JVM系列文章(四):类载入机制

    作为一个程序猿,只知道怎么用是远远不够的. 起码,你须要知道为什么能够这么用.即我们所谓底层的东西. 那究竟什么是底层呢?我认为这不能一概而论.以我如今的知识水平而言:对于Web开发人员,TCP/IP ...

  2. 深入研究Java类载入机制

    深入研究Java类载入机制   类载入是Java程序运行的第一步,研究类的载入有助于了解JVM运行过程,并指导开发人员採取更有效的措施配合程序运行. 研究类载入机制的第二个目的是让程序能动态的控制类载 ...

  3. 深入java虚拟机学习 -- 类的加载机制

    当看到"类的加载机制",肯定很多人都在想我平时也不接触啊,工作中无非就是写代码,不会了可以百度,至于类,jvm是怎么加载的我一点也不需要关心.在我刚开始工作的时候也觉得这些底层的内 ...

  4. 深入java虚拟机学习 -- 类的加载机制(续)

    昨晚写 深入java虚拟机学习 -- 类的加载机制 都到1点半了,由于第二天还要工作,没有将上篇文章中的demo讲解写出来,今天抽时间补上昨晚的例子讲解. 这里我先把昨天的两份代码贴过来,重新看下: ...

  5. 黑马程序猿——Java中的类载入器

    ------- android培训.java培训.期待与您交流! -------- 类载入器 Java虚拟机中能够安装多个类载入器,系统默认三个主要类载入器,每一个类负责载入特定位置的类: BootS ...

  6. java虚拟机(一)——内存管理机制与OOM异常

    一  java内存区域与内存溢出异常(OOM) 1)运行时数据区域划分        1.程序计数器(Program Conuter Register) 程序计数器是一块较小的内存空间,它是当前线程执 ...

  7. 深入java虚拟机学习 -- 类的卸载

    类的生命周期 在开始本节之前让我们再来回顾下类的生命周期 没看过前6个过程的同学建议从头看下<深入java虚拟机学习 -- 类的加载机制>,这里就不再过多介绍了,着重说下类的卸载 类的卸载 ...

  8. DexClassLoader和PathClassLoader类载入机制

    0x00 在DexClassLoader和PathClassLoader载入Dex流程一文中,我们分析了dex文件怎样形成了DexFile结构体.本文中解说类载入机制,实际上就是生成ClassObje ...

  9. 《深入理解 Java 虚拟机》学习 -- 类加载机制

    <深入理解 Java 虚拟机>学习 -- 类加载机制 1. 概述 虚拟机把描述类的数据从 Class 文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的 J ...

随机推荐

  1. pandas深入理解

    Pandas是一个Python库,旨在通过“标记”和“关系”数据以完成数据整理工作,库中有两个主要的数据结构Series和DataFrame In [1]: import numpy as np In ...

  2. kettle 使用excel模板导出数据

    通过excel进行高速开发报表: 建设思路: 1.首先制订相关的execl模板. 2.通过etl工具(kettle)能够高速的 将数据库中的数据按excel模板导出成新的excel就可以. 当中ket ...

  3. sql不显示反复列

    在报表里,基本上都能够把反复的资料不显示,在SQL里怎么才干做到例如以下情况呢? a 10 a 20 b 30 b 40 b 50 显示为: a 10 20 b 30 40 50 SQL 例如以下: ...

  4. 超高性能管线式HTTP请求(实践·原理·实现)

    超高性能管线式HTTP请求(实践·原理·实现) 一.总结 一句话总结:实际pipe早就被http1.1所支持,并且大部分nginx服务器也支持并开启了这一功能. pipe之所以能比常规请求方式性能高出 ...

  5. php的分页代码

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. CALayer初认识

    CALayer :CA就是coreAnimation 核心动画 它是同时支持 Mac OS 和 iOS系统的 所有的核心动画都是通过CALayer来实现的 UIView本身是不具备显示功能的 是它内部 ...

  7. BZOJ 4129 树上带修莫队+线段树

    思路: 可以先做做BZOJ3585 是序列上的mex 考虑莫队的转移 如果当前数字出现过 线段树上把它置成1 对于询问 二分ans 线段树上查 0到ans的和 是不是ans+1 本题就是把它搞到了序列 ...

  8. BZOJ 1989 概率相关

    思路: 一条边免费的概率为 (经过它的路/总路径条数)^2 DFS即可 有个地方没有用 long long炸了好久- //By SiriusRen #include <cstdio> us ...

  9. Creative Cloud 无法连接问题

    防火墙允许 PDApp.exe Windows:Program Files\Common Files\Adobe\OOBE\PDApp\core Mac OS:应用程序 > 实用工具 > ...

  10. iOS构建流畅的交互界面--CPU,GPU资源消耗的原因和解决方案

    CPU资源消耗的原因和解决方案对象创建轻量对象代替重量对象* 不需要响应触摸事件的控件:CALayer显示* 对象不涉及UI操作,则尽量放到后台线程创建* 包含有CALayer的控件只能在主线程创建和 ...