jvm使用java类的方式
- java源程序经过java编译器编译之后转换成java字节码文件(.class) ,类加载器负责读取java字节码文件,并把此字节码转换成java.lang.Class类的一个实例,每个实例用来表示一个java类,可以通过实例的newInstance()函数创建出类的一个实例对象。
类加载器介绍
基本上所有的类加载器都是java.lang.ClassLoadeer类的一个实例(实现类)
类加载器的职责就是根据一个指定类的名称,找到此类并生成相应的字节码,并生成一个Class类型的实例,加载器还负责加载java所需的一系列资源
类加载器系统结构
-引导类加载器(bootstrap class loader):用来加载java的核心类库,是用原生代码实现的
- 原生代码:被编译后直接依附于系统运行,不需要通过虚拟机,汇编成cpu的目标执行文件
-扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
-系统类加载器(system class loader):用来加载java应用的类路径(自己写的java应用),获取此加载器通过ClassLoader.getSystemClassLoader()获取
自己定义的类加载器 需要继承java.lang.ClassLoader类
除了引导类加载器外,其他加载器都有一个父加载器,对于系统提供的类加载器来说,系统类加载器的父类加载器是扩展类加载器,而扩展类加载器的父类加载器是引导类加载器;对于开发人员编写的类加载器来说,其父类加载器是加载此类加载器 Java 类的类加载器。因为类加载器 Java 类如同其它的 Java 类一样,也是要由类加载器来加载的。一般来说,开发人员编写的类加载器的父类加载器是系统类加载器。
类加载器的代理模式(双亲委派机制)
- 描述:某个特定的类加载器在接收到加载类的请求时,首先将请求委托给父类加载器,如果父类加载成功,就成功返回
类的加载过程
- 在前面介绍类加载器的代理模式的时候,提到过类加载器会首先代理给其它类加载器来尝试加载某个类。这就意味着真正完成类的加载工作的类加载器和启动这个加载过程的类加载器,有可能不是同一个。真正完成类的加载工作是通过调用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方法不会被重复调用。