Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2877864
  • 博文数量: 471
  • 博客积分: 7081
  • 博客等级: 少将
  • 技术积分: 5369
  • 用 户 组: 普通用户
  • 注册时间: 2012-01-04 21:55
文章分类

全部博文(471)

文章存档

2014年(90)

2013年(69)

2012年(312)

分类: Java

2012-02-28 19:54:03

1、什么是类加载器和类加载器的作用
   类加载器就是加载类的工具,把.class这些二进制字节码处理加载到内存来,这就是加载器的作用。
   Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责    加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader
类加载器也是Java类,因为其他java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是不是java类,这正是BootStrap。Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载。图中是jdk下的JRE包

当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?

  • 首先当前线程的类加载器去加载线程中的第一个类。如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。 还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
  • 每个类加载器加载类时,又先委托给其上级类加载器。当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个呢?对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的itcast.jar包中后,运行结果为ExtClassLoader的原因。
  1. public class ClassLoderTest {

  2.     public static void main(String[] args) {

  3.         /*
  4.          * 这个二进制class肯定有一个类加载进来的(要不怎么运行),
  5.          * ClassLoderTest.class.getClassLoader()得到一个类加载器,
  6.          * 类加载器是一个对象,这个对象是用类搞出来的.getName就可以得到这个类的名字
  7.          */
  8.         String className=ClassLoderTest.class.getClassLoader().getClass().getName();
  9.         System.out.println("本类的加载器名字"+className);
  10.         String sysName=System.class.getClassLoader().getClass().getName();
  11.         System.out.println("本类的加载器名字"+className);//由此证明bootStrap不是java写的
  12.         
  13.     }

  14. }

    输出:
  15. 本类的加载器名字sun.misc.Launcher$AppClassLoader
  16. Exception in thread "main" java.lang.NullPointerException
  17. at cn.itcast.day3.ClassLoderTest.main(ClassLoderTest.java:19)
那么对于调用哪个加载器,是怎样委托的呢,首先 AppClassLoader  委托 ExtClassLoader, , ExtClassLoader 委托BootStrap在各自的范围寻找 ClassLoderTest.jar,如果父类都没找到就向下回到 AppClassLoader。

我们生成一个ClassLoderTest.jar放到ExtClassLoader管辖的目录下,看运行结果
已经在第一个父类没找到,第二个父类,就不在向下找

  1. 输出:
    本类的加载器名字sun.misc.Launcher$ExtClassLoader

类加载器的委托机制:



当Java虚拟机要加载一个类时,到底该派哪个类加载器去加载呢?
1.首先是当前线程的类加载器去加载线程中的第一个类。
2.如果类A中引用了类B,Java虚拟机将使用加载类A的类加载器来加载类B。
3.还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。

每个类加载器加载类时,又先委托给其上级类加载器。
1.当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛出ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChlid方法,即使有,那么有多个儿子,找哪一个呢?

有一道面试题:
能不能自己写个类叫java.lang.System?一般情况下不能,因为类加载采用委托机制,这样可以保证爸爸们优先,也就是总是使用爸爸们能找到的类,这样总是使用java系统提供的System。因为“每个类加载器加载类时,又先委托给其上级类加载器”,java.lang.System在BootStrap中最先加载。但是我们可以写一个类加载器来加载我们自己写的java.lang.System类。



阅读(901) | 评论(4) | 转发(0) |
给主人留下些什么吧!~~

nba76ers2017-12-18 15:16:56

类加载器ClassLoader概述
http://blog.csdn.net/tangyangguang/article/details/8878302

nba76ers2017-12-18 15:00:53

1、JAVA_HOME(Windows不区分大小写,Linux系统是区分大小写的) JDK的安装路径。

博主的JDK默认安装的,C:\\Program Files\\Java\\jdk1.8.0_91 JAVA_HOME本身并没有什么意义,其目的方便对PATH和CLASSPATH路径的配置 JAVA_HOME本身 并没有什么意义,其目的方便对PATH和CLASSPATH路径的配置  

2、PATH 既然在计算机里安装了JDK,而JDK的安装路径下也包含了java和javac两个命令,但计算机不知道从哪里找 到这两个命令。如果能找到这个命令,则改命令是可执行的。  即:C:\\Program Files\\Java\\jdk1.8.0_91\\bin。 当然,如果你设置JAVA_HOME,也可以%JAVA_HOME%\\bin; 当JAVA_HOME值改变时,不必修改PATH。 

3、CLASSPATH 在配置完成PATH后,完全可以正常编译Java类,并在当前路径下产生class文件。当使用java命令执行类时,JRE应带去哪里搜索Java类呢?所以用CLAS

nba76ers2017-12-18 14:43:08

nba76ers:注意,rt.jar就是java(uitl lang ...)的类库放在 G:\Program Files (x86)\Java\jdk1.6.0_07\jre\lib下 ,也就是父类管辖的,那么他就优先加载,所以就不能自己写system 这些类,给自己用,除非放到那个目录下

我们都知道classloader的getResource、getResources等方法可以加载classpath中的资源。classloader获取资源传入的参数是相对于classpath的相对路径,如果某个资源想要被classloader的加载到就要放到当前的classpath中,或者把资源所在的目录或者jar包文件作为classpath。

     Java程序在启动时可以指定多个位置作为classpath,每个位置都可以用URL来描述,不同的位置之间用分号分隔。根据Java命令的提示,目录、jar文件或者普通的zip文件都可以作为虚拟机识别的classpath。

     那么虚拟机是怎样利用这些位置加载资源的呢,下面深入JDK的源码来探究一下。众所周知,负责加载应用程序的类和资源的类加载器是AppClassloader,其实加载一个类之前也是先把类的名字转换成资源的名字,先加载.class类文件的资源再从中加载出具体的类对象。那么先来看AppClassloader的创建

回复 | 举报

nba76ers2012-02-28 20:48:13

注意,rt.jar就是java(uitl lang ...)的类库放在 G:\Program Files (x86)\Java\jdk1.6.0_07\jre\lib下 ,也就是父类管辖的,那么他就优先加载,所以就不能自己写system 这些类,给自己用,除非放到那个目录下