深入java虚拟机——类加载器_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > 深入java虚拟机——类加载器

深入java虚拟机——类加载器

 2015/3/25 12:45:15  yucang52555  程序员俱乐部  我要评论(0)
  • 摘要:类加载器完全可以说是是Java语言的一个创新,也是Java语言流行的重要原因之一。它使得Java类可以被动态加载到Java虚拟机中并执行。Java虚拟机使用Java类的方式如下:Java源程序(.java文件)在经过Java编译器编译之后就被转换成Java字节码(.class文件)。类加载器负责读取Java字节码,并转换成java.lang.Class类的一个实例。每个这样的实例用来表示一个Java类。通过此实例的newInstance()方法就可以创建出该类的一个对象。实际的情况可能更加复杂
  • 标签:Java 虚拟机

? ? 类加载器完全可以说是是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一。它使得 Java 类可以被动态加载到 Java 虚拟机中并执行。

? ? Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节码(.class 文件)。类加载器负责读取 Java 字节码,并转换成monospace; line-height: 1.5em; font-size: 0.95em !important;">java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的?newInstance()方法就可以创建出该类的一个对象。实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。基本上所有的类加载器都是?java.lang.ClassLoader类的一个实例。

? ? 首先,我们讲一下类的加载过程。

? ? ? JVM将类加载过程分为三个步骤:装载(Load),链接(Link)和初始化(Initialize)。其中链接又分为:验证,准备,解析三个阶段。各个步骤执行操作如下:

? ? ??1) 装载:查找并加载类的二进制数据;

? ? ? 2)链接:

验证:确保被加载类的正确性;

准备:为类的静态变量分配内存,并将其初始化为默认值;

解析:把类中的符号引用转换为直接引用;

? ? ? 3)初始化:为类的静态变量赋予正确的初始值;

? ? ? 也需要说明一下,验证这一步存在的必要性。

? ? ? 如果由编译器生成的class文件,它肯定是符合JVM字节码格式的,但是万一有高手自己写一个class文件,让JVM加载并运行,用于恶意用途,就不妙了,因此这个class文件要先过验证这一关,不符合的话不会让它继续执行的,也是为了安全考虑吧。

?

? ? ? 接下来,我们看一下类的加载具体操作。

? ? ??类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个这个类的java.lang.Class对象,用来封装类在方法区类的对象。由此我们可以得出:

? ? (1)类的加载的最终产品是位于堆区中的Class对象;

? ? (2)Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口

? ? ? JVM的类加载是通过ClassLoader及其子类来完成的,类的层次关系和加载顺序可以由下图来描述:


?Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的。系统提供的类加载器主要有下面三个:

(1)引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自?java.lang.ClassLoader

(2)扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。

(3)系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过?ClassLoader.getSystemClassLoader()来获取它。

? ? ? 除了系统提供的类加载器以外,开发人员可以通过继承?java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求。

? ? ??真正完成类的加载工作是通过调用?defineClass来实现的;而启动类的加载过程是通过调用?loadClass来实现的。前者称为一个类的定义加载器(defining loader),后者称为初始加载器(initiating loader)。在 Java 虚拟机判断两个类是否相同的时候,使用的是类的定义加载器。也就是说,哪个类加载器启动类的加载过程并不重要,重要的是最终定义这个类的加载器。两种类加载器的关联之处在于:一个类的定义加载器是它引用的其它类的初始加载器。

? ? ? 如类?com.example.Outer引用了类com.example.Inner,则由类?com.example.Outer的定义加载器负责启动类?com.example.Inner的加载过程。方法?loadClass()抛出的是?java.lang.ClassNotFoundException异常;方法?defineClass()抛出的是java.lang.NoClassDefFoundError异常。

? ? ? 类加载器在成功加载某个类之后,会把得到的?java.lang.Class类的实例缓存起来。下次再请求加载该类的时候,类加载器会直接使用缓存的类的实例,而不会尝试再次加载。也就是说,对于一个类加载器实例来说,相同全名的类只加载一次,即?loadClass方法不会被重复调用。

?

程序猿行业技术生活交流群:181287753(指尖天下),欢迎大伙加入交流学习。

  • 大小: 180.7 KB
  • 查看图片附件
上一篇: Spring定时器详细配置 下一篇: 没有下一篇了!
发表评论
用户名: 匿名