欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

java 类加载器,

来源: javaer 分享于  点击 18874 次 点评:49

java 类加载器,


获得一个类所在的jar包

  1. ProtectionDomain pd = StringUtils.class.getProtectionDomain();  
  2.   CodeSource cs = pd.getCodeSource();  
  3.   System.out.println(cs.getLocation());  

由系统类加载器所加载的类不能使用该方法来获取路径。


类的加载过程

类的加载过程分为:装载、链接、初始化。

(1)装载,查找并加载类的字节码文件。

(2)链接

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

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

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

(3)初始化,为类的静态变量赋予正确的初始值。

在一个类加载器中,类只能初始化一次。


在堆区创建类的java.lang.class对象。class对象封装了类在方法区内的数据结构,提供了访问方法区内的数据结构和接口。


类加载器

JVM的类加载是通过ClassLoader及其子类来完成的。ClassLoader还负责加载 Java 应用所需的资源,如图像文件和配置文件等。
类加载器的加载顺序:

1)Bootstrap ClassLoader

负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类

2)Extension ClassLoader

负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目录下的jar包

3)App ClassLoader(system class loader)

负责记载classpath中指定的jar包及目录中class,java应用的类都是由它完成加载的。通过ClassLoader.getSystemClassLoader()来获取它。

4)Custom ClassLoader

属于应用程序根据自身需要自定义的ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现ClassLoader。


除了引导类加载器之外,所有的类加载器都有一个父类加载器。

系统类加载器的父类加载器是扩展类加载器,扩展类加载器的父类加载器是引导类加载器。

对于Custom ClassLoader,其父类加载器是加载此类加载器java类的类加载器。类加载器java类也是由类加载器来加载的。一般Custom ClassLoader的父类加载器是系统类加载器。

每个java类都维护着一个指向加载该类的类加载器的引用。


类加载器的代理模式

类加载器在尝试自己去查找某个类的字节代码并定义它时,会先代理给其父类加载器,由父类加载器先去尝试加载这个类,以此类推。这意味着真正完成类的加载工作的类加载器和启动这个加载过程的类加载器,有可能不是同一个。真正完成类的加载工作是通过调用defineClass来实现的,称之为一个类的定义加载器,而启动类的加载过程是通过调用loadClass来实现的,称为初始加载器。在JVM判断两个类是否相同的时候,使用的是类的定义加载器,也就是重要的是最终定义这个类的加载器。两种类加载器的关联之处在于:一个类的定义加载器是它引用的其他类的初始加载器。加载器中方法loadClass()抛出的是java.lang.ClassNotFoundException异常。方法defineClass()抛出的是java.lang.NoClassDefFoundError。 代理模式是为了保证java核心库的类型安全。通过代理模式,对于java核心库的类的加载工作由引导类加载器来统一完成,保证了java应用所使用的都是同一版本的java核心库的类,是互相兼容的。 不同的类加载器为相同名称的类创建了额外的名称空间。相同名称的类可以并存在java虚拟机中,只需要用不同的类加载器来加载它们即可。不同类加载器加载的类之间是不兼容的。 JVM不仅看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后得到的类,也是不同的。试图对这两个类的对象进行相互赋值,会抛出运行时异常,ClasscastException。

线程上下文类加载器

类java.lang.Thread中的方法getContextClassLoader()和setContextClassLoader()用来获取和设置线程的上下文类加载器。如果没有设置的话,线程将继承其父线程的上下文类加载器。java应用运行的初始线程的上下文类加载器是系统类加载器。在线程中运行的代码可以通过此类加载器来加载类和资源。

Custom ClassLoader

ClassLoader中与加载类相关的方法
方法 说明
getParent() 返回该类加载器的父类加载器。
loadClass(String name) 加载名称为 name的类,返回的结果是 java.lang.Class类的实例。
findClass(String name) 查找名称为 name的类,返回的结果是 java.lang.Class类的实例。
findLoadedClass(String name) 查找名称为 name的已经被加载过的类,返回的结果是 java.lang.Class类的实例。
defineClass(String name, byte[] b, int off, int len) 把字节数组 b中的内容转换成 Java 类,返回的结果是 java.lang.Class类的实例。这个方法被声明为 final的。
resolveClass(Class<?> c) 链接指定的 Java 类。
一般来说,自定义的类加载器只需要覆盖findClass(String name)即可,查找类的字节代码文件,然后读取该文件内容,最后通过defineClass()来把这些字节代码转换成java.lang.Class类的实例。 java.lang.ClassLoader类的方法loadClass()封装了代理模式的实现,首先调用findLoadedClass()方法来检查该类是否已经被加载过,如果没有加载过的话,会调用父类加载器的loadClass()来尝试加载该类。如果父类加载器无法加载该类的话,就调用findClass()方法来查找该类。






相关文章

    暂无相关文章
相关栏目:

用户点评