【学习札记-类加载器】

个人学习整理,如有不足之处,请不吝指教。转载请注明:@CSU-Max

类加载器

简介

类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个
Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。

类加载器的分类

Java 中的类加载器的分类如下图,看图简洁明了:

启动类加载器(bootstrap class loader):加载 Java 的核心库。比如位于<JAVA_HOME>/jre/lib 目录下的vm.jar,core.jar。

扩展类加载器(extensions class loader):加载 Java 的扩展库。一般位于<JAVA_HOME>/jre/lib/ext 或者通过java.ext.dirs 这个系统属性指定的路径下的代码。这个类加载器是由sun.misc.Launcher$ExtClassLoader
实现的。

系统类加载器(system class loader):根据 Java 应用的类路径(CLASSPATH)来加载
Java 类。加载java.class.path(映射系统参数 CLASSPATH的值) 路径下面的代码,这个类加载器是由 sun.misc.Launcher$AppClassLoader 实现的。

类加载器的层次结构和双亲委派模型

分析

除了启动类加载器,所有的类加载器对象都有一个可以作为其双亲的类加载器对象。

通过 ClassLoader 类的 getParent 方法可以获取双亲类加载器对象。

我们自定义的类加载器 Java 类继承自 ClassLoader 类,而 ClassLoader 类的构造方法中可以指定类加载器的双亲类加载器对象,所以我们可以在自定义的类加载器的构造方法中调用父类 ClassLoader 
类的构造方法,指定双亲类加载器对象的值。

若我们在自定义类加载器时没有指定双亲类加载器,则默认的双亲类加载器是系统类加载器。

若当前类加载器对象的双亲类加载器是启动类加载器,则其 getParent 方法返回 null。

下面是测试代码:

public void test()
    {
        ClassLoader cl = getClass().getClassLoader();
        System.out.println(cl.toString());
        if (cl != null)
        {
            cl = cl.getParent();
            System.out.println(cl.toString());
        }
    }

测试结果:

[email protected]       ---> 默认为系统类加载器

[email protected]      
---> getParent方法得到扩展类加载器

---> getParent方法返回null

通过以上的简单代码和输出结果可以很好的说明我们上面的说法。

根据以上的分析,我们可以发现这种加载的过程形成了一种层次结构,这种层次结构可以用如下简图表示:

            

没有自己定义的类加载器时                                      有自己定义的类加载器时

概念

一般应用程序都是由以上三种基本的类加载器加载的,当然,有时候也会使用我们自定义的类加载器。这些类加载器构成了一种层次结构,称为类加载器的双亲委派模型。

所有的类加载器(除了启动类加载器)对象都有一个可以作为其双亲的类加载器对象,通过组合关系来复用双亲类加载器的方法。

原理

当一个类加载器收到类加载请求时,它并不会第一时间自己去加载这个类,而是把该请求委派给双亲类加载器去完成,每个层次的类加载器都是如此(双亲类加载器再将请求委派给它的双亲类加载器),如果双亲类加载器可以完成类加载任务,就成功返回;只有当双亲类加载器无法完成该加载请求时(它的搜索范围内没有找到所需要的类),子类加载器才会自己去加载。(此处可以通俗的理解为递归)

实现

关于虚拟机中默认的双亲委派机制,我们可以查看 java.lang.ClassLoader 类的 loadClass
方法,源码及分析如下:

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 首先判断请求的类是否已经被加载过了
            Class c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                //如果没有被加载,接着就检查双亲类加载器是否存在
                try {
                    if (parent != null) {
                        //如果双亲类加载器存在,就调用其loadClass方法
                        c = parent.loadClass(name, false);
                    } else {
                        //如果不存在双亲类加载器,就检查是否使用启动类加载器加载该类
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {

                }

                if (c == null) {
                    long t1 = System.nanoTime();
                    //如果依旧不能被加载,则调用自身的findClass来进行类加载
                    c = findClass(name);
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

最近在看 java 虚拟机这一块,将自己的一些学习心得记录下来,分享给大家,多多指教。

***************************************************************************

*  转载请注明出处:  @CSU-Max   http://blog.csdn.net/csu_max 
    *

***************************************************************************

【学习札记-类加载器】

时间: 2024-12-23 08:46:31

【学习札记-类加载器】的相关文章

Java虚拟机JVM学习05 类加载器的父委托机制

Java虚拟机JVM学习05 类加载器的父委托机制 类加载器 类加载器用来把类加载到Java虚拟机中. 类加载器的类型 有两种类型的类加载器: 1.JVM自带的加载器: 根类加载器(Bootstrap) 扩展类加载器(Extension) 系统类加载器(System) 2.用户自定义的类加载器: java.lang.ClassLoader的子类,用户可以定制类的加载方式. JVM自带的加载器 Java虚拟机自带了以下几种加载器. 1.根(Bootstrap)类加载器: 该加载器没有父加载器. 它

类加载机制的学习1______类加载器

在学习类加载机制之前,我们先了解一下类加载器,因为类加载器是类加载机制的前提.类加载器的主要任务就是:根据一个类的全限定名,将该类的字节码文件加载进JVM中,然后转换为一个对应类的Java.lang.Class对象实例.程序员也可以自定义类加载器,一般的将派生于抽象类ClassLoader的类加载器都划分为自定义类加载器. 在程序中我们最常见的类加载器时钟只有三个: Bootstrap ClassLoader ExtClassLoader: AppClassLoader:(加载classpath

JavaEE学习之类加载器

类装载子系统 在JAVA虚拟机中,负责查找并装载类型的那部分被称为类装载子系统. JAVA虚拟机有两种类装载器:启动类装载器和用户自定义类装载器.前者是JAVA虚拟机实现的一部分,后者则是Java程序的一部分.由不同的类装载器装载的类将被放在虚拟机内部的不同命名空间中. 类装载器子系统涉及Java虚拟机的其他几个组成部分,以及几个来自java.lang库的类.比如,用户自定义的类装载器是普通的Java对象,它的类必须派生自java.lang.ClassLoader类.ClassLoader中定义

JVM学习记录-类加载器

前言 JVM设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作房东Java虚拟机外面去实现,以便让应用程序自己决定如何去获取所需要的类.实现这个动作的代码模块称为“类加载器”. 类与类加载器 类加载器虽然只用户实现类的加载动作,但它在Java程序中起到的作用却远远不限于类加载阶段.每个类都有一个独立的类名称空间,在比较两个类是否“相等”,只有两个类是由同一个类加载器加载的前提下才有意义,否则即使两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载它们的

【JAVAWEB学习笔记】25_基础加强:类加载器、注解 @xxx和动态代理

基础加强 学习目标 案例-自定义单元测试@MyTest 案例-全局的编码的解决 一.类加载器 1.什么是类加载器,作用是什么? 类加载器就加载字节码文件(.class) 2.类加载器的种类 类加载器有三种,不同类加载器加载不同的 1)BootStrap:引导类加载器:加载都是最基础的文件 2)ExtClassLoader:扩展类加载器:加载都是基础的文件 3)AppClassLoader:应用类加载器:三方jar包和自己编写java文件 怎么获得类加载器?(重点) ClassLoader 字节码

第17天(基础加强_注解_类加载器_动态代理)_学习目标版本

学习目标 能够使用Junit进行单元测试 能够说出注解的作用 能够使用JDK提供的3个注解 能够根据基本语法编写自定义注解实现类 能够了解自定义注解解析 能够了解元注解使用 能够根据上课案例分析,编写模拟@Test案例 能够理解动态代理原理 能够使用动态代理Proxy编写代理类 Junit单元测试 Junit介绍 JUnit是一个Java语言的单元测试框架,简单理解为可以用于取代java的main方法.Junit属于第三方工具,一般情况下需要导入jar包,不过,多数Java开发环境已经集成了JU

框架学习前基础加强 泛型,注解,反射(泛型&注解)应用案例,IOC,Servlet3.0,动态代理,类加载器

泛型 1. 泛型类 :具有一个或多个类型变量的类,称之为泛型类! class A<T> { } 2. 在创建泛型类实例时,需要为其类型变量赋值 A<String> a = new A<String>(); * 如果创建实例时,不给类型变量赋值,那么会有一个警告! 3. 泛型方法 :具有一个或多个类型变量的方法,称之为泛型方法! class A<T> { public T fun(T t1) {} } fun()方法不是泛型方法!它是泛型类中的一个方法! pu

java类加载器学习2——自定义类加载器和父类委托机制带来的问题

一.自定义类加载器的一般步骤 Java的类加载器自从JDK1.2开始便引入了一条机制叫做父类委托机制.一个类需要被加载的时候,JVM先会调用他的父类加载器进行加载,父类调用父类的父类,一直到顶级类加载器.如果父类加载器加载不了,依次再使用其子类进行加载.当然这类所说的父类加载器,不一定他们之间是继承的关系,有可能仅仅是包装的关系. Java之所以出现这条机制,因为是处于安全性考虑.害怕用户自己定义class文件然后自己写一个类加载器来加载原本应该是JVM自己加载的类.这样会是JVM虚拟机混乱或者

jvm学习二:类加载器

前一节详细的聊了一下类的加载过程,本节聊一聊类的加载工具,类加载器  ---  ClassLoader 本想自己写的,查资料的时候查到一篇大神的文章,写的十分详细 大家直接过去看吧http://blog.csdn.net/zhoudaxia/article/details/35824249