Java的Classloader

来源:互联网 发布:生活中的禁忌知乎 编辑:程序博客网 时间:2024/05/01 22:42
 
      我相信许多刚刚入手java的朋友是不会去主动了解classloader的,而一些已经用了java一段时间的朋友对这个概念肯定也并不很清楚,但是了解classloader的基本原理对于开发是有很大好处的,所以这里会简要介绍一些,只是简要介绍,我本人也只是很基本的了解,因为classloader在java中本身就是一个非常底层的概念,更有甚于你可以写你自己的classloader,当然我是还没到那个水平。
      首先我要假设阅读的人已经基本了解了c/c++这类语言的运行过程,也就是直接编译成二进制文件,最后根据二进制指令码,一条条的执行指令。但是对于java这类解释性语言javac编译器是先将源码编译成class中间代码的,机器自然不懂得什么叫中间代码于是就通过jvm来把中间代码转换成计算机认识的机器代码。而通常第一步就是让classloader(类加载器)去加载相应的class文件,即类文件。综上所述,classloader事实上是jvm加载中间代码,或者说是类文件的工具!
      那classloader是怎么知道运行这个程序需要加载哪些类文件呢?事实上大多数的源码中你都显示的告诉了classloader所要加载的类文件,这就是import语句的作用!然而有些时候你发现运行System.out.println或者用到String类时没有任何显示的import语句程序在运行时也不会报ClassNotFoundException这样的运行时错误。这又是怎么回事呢?
       这要从classloader的基本结构解释!java中至少三种classloader(也就是说jdk提供三种,你也可以自己实现):The bootstrap classloader;The extension classloader;the application classloader。
       bootstrap是最核心的classloader,是jvm自带的,他负责加载系统类,比如java.lang.* 就是属于系统类,但是并不是说系统类就不需要显示的import了,只是java.lang.*不需要,java在每次运行的时候都会自动加载这个包里面的所有类。而事实上所谓的系统类就是rt.jar(这个文件位于java安装目录下的/jre/lib目录下)jar包中的类。关于第二种classloader,它是负责加载所谓的标准扩展类的,究竟什么是标准扩展类的,就是一切放在jdk安装目录下的/jre/lib/ext目录下的类文件和jar包。第一和第二中classloader,都不需要通过classpath来告诉classloader要加载的类都是哪里,因为他们的位置都是java指定好了的,并且是静态的,不能改变的!第三种是类加载器就负责加载应用程序所定义的类(就是你自己写的A类,B类或者是非官方的插件等等),这些类需要放在你所设置的classpath中,而classpath(类路径)的作用就是告诉第三种类加载器到哪里去加载应用程序所定义的类。
      java中的classloader是有父子关系的除bootstrap的任何一个classloader都有一个父亲,bootstrap事实上就是树的根了,它的孩子是extension classloader,而application classloader是extension的孩子。当一个classloader要加载一个类是,它总是先给它的父亲一个机会去加载类,只有当父亲找不到或加载失败时它才加载。比如说你自己定义了一个String类,而且自己造了一个java.lang包,把这个类放在了这个包里,那么负责加载的应该是application classloader但是application先把权力让给父亲extensiion而extension又把权力让给了bootstrap而bootstrap在rt.jar里也发现了一个java.lang.String,所以他就把这个String给加载了,而整个加载过程也结束了,这时你加载的是系统的那个java.lang.String而不是你自己的那个!
      最后要注意的是每个类都有一个Class类成员变量(java的reflection就是通过它来实现的)。里面有一个getClassLoader()方法可以得到负责加载该类的类加载器对象。但是bootstrap比较特殊,它是整合在jvm里的,而jvm本身是用c实现的,根本不存在对象这一说。所以像String这样的类你调用String.class.getClassLoader()的话返回的是null!
原创粉丝点击