zoukankan      html  css  js  c++  java
  • 类加载器

    一般来说,java虚拟机使用一个类的方式如下:java源程序在经过java编译器编译之后就被转换成java字节码文件.class,虚拟机加载字节码文件被转换为java.lang.Class的一个实例,每个这样的实例代表一个java类,然后通过这个实例的newInstance()方法生成一个对象。基本上所有类加载器都是java.lang.ClassLoader的实例。
     
    java.lang.ClassLoader的主要作用是根据一个给定类的名字,查找该类的字节码文件,并生成一个class实例,它同时也加载java类所需要的一些资源如图像和配置文件。
     
    java.lang.ClassLoader类介绍
     
    java.lang.ClassLoader与加载类有关的方法
     
    | 方法                         | 说明                                                  |
    |------------------------------+-------------------------------------------------------|
    | getParent()                  | 返回该类加载器的父加载器                              |
    | loadClass(String name)       | 加载名称为name的类,返回结果是java.lang.Class的实例   |
    | findClass(String name)       | 查找名称为name的类,返回结果是java.lang.Class类的实例 |
    | findLoadedClass(String name) | 查找名字为name的已经加载过的类,返回结果同上          |
    | defineClass()                | 把字节数组b中的内容转换成java类,返回结果同上         |
    | resolveClass(Class<?> c)     | 连接指定的java类                                      |
     
    类加载器的树状组织结构
     
    java中的类加载器分为两种,一种是系统提供的,另一种是由java应用开发人员编写的。
     
    java中系统提供的类加载器有三种:
    •引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,加载系统类(通常从jar文件rt.jar中进行加载),它是虚拟机整体中的一部分,通常用原生代码C来实现的,并不继承自java.lang.ClassLoader,使用String.class.getClassLoader()将返回null。
    •扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录(jre/lib/ext)。该类加载器在此目录里面查找并加载 Java 类。
    •系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。
     
    扩展类加载器和系统类加载器通常都是由java实现的,它们都是URLClassLoader类的实例。Class.forName()是使用系统类加载器加载的。
     
    除了引导类加载器外,每个类加载器都有一个父类加载器, 通过getParent()方法可以得到,类加载器会为它的父类加载器提供一个机会,以便加载任何给定类,只有在其父类加载器加载失败时,它才会加载给定类。
     
    类加载器树状组织结构示意图
    类加载器

    类加载器的代理模式
     
    在介绍代理模式背后的动机之前,首先需要说明一下 Java 虚拟机是如何判定两个 Java 类是相同的。Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。比如一个 Java 类 com.example.Sample,编译之后生成了字节代码文件Sample.class。两个不同的类加载器 ClassLoaderA和 ClassLoaderB分别读取了这个Sample.class文件,并定义出两个 java.lang.Class类的实例来表示这个类。这
    两个实例是不相同的。对于 Java 虚拟机来说,它们是不同的类。试图对这两个类的对象进行相互赋值,会抛出运行时异常 ClassCastException。
     
    了解了这一点之后,就可以理解代理模式的设计动机了。代理模式是为了保证 Java 核心库的类型安全。所有 Java 应用都至少需要引用 java.lang.Object类,也就是说在运行的时候,java.lang.Object这个类需要被加载到 Java 虚拟机中。如果这个加载过程由 Java 应用自己的类加载器来完成的话,很可能就存在多个版本的 java.lang.Object类,而且这些类之间是不兼容的。通过代理模式,对于 Java 核心库的类的加载工作由引导类加载器来统一完成,保证了 Java 应用所使用的都是同一个版本的 Java 核心库的类,是互相兼容的。
     
    网络类加载器
     
    Java 字节代码(.class)文件存放在服务器上,客户端通过网络的方式获取字节代码并执行。当有版本更新的时候,只需要替换掉服务器上保存的文件即可。通过类加载器可以比较简单的实现这种需求。类 NetworkClassLoader负责通过网络下载 Java 类字节代码并定义出 Java 类。它的实现与 FileSystemClassLoader类似。在通过 NetworkClassLoader加载了某个版本的类之后,一般有两种做法来使用它。第一种做法是使用 Java 反射API。另外一种做法是使用接口。
     
    需要注意的是,并不能直接在客户端代码中引用从服务器上下载的类,因为客户端代码的类加载器找不到这些类。使用 Java 反射 API 可以直接调用 Java 类的方法。而使用接口的做法则是把接口的类放在客户端中,从服务器上加载实现此接口的不同版本的类。在客户端通过相同的接口来使用这些实现类。
     
    两种加载类的方法以及区别
     
    有两种手动加载类的方法:ClassLoader.loadClass()和Class.forName()而Class.forName()实际上也是调用类加载器的loadClass方法。两者也存在一些区别
     
    JVM加载类的时候,需要经过三个步骤:装载、连接和初始化。
    装载就是找到相应的class文件,读入JVM;
    初始化就是对class文件的初始化;
    连接分为三步:
    + 验证class文件是否符合规格
    + 准备 为类变量分配内存的同时设置默认初始值
    + 解释 根据loadClass方法第二个参数判定是否需要解释,这里的解释是指根据类中的符号引用查找响应的实体,再把符号引用替换成一个直接引用的过程
     
    Class.forName()调用Class.forName(name, initialize, loader);因此Class.forName("classString")等同于Class.forName("classString",true, CALLCLASS.class.getClassLoader())第二个参数为true,设置加载类的时候连接该类
     
    用户使用类加载器加载类ClassLoader.loadClass(name),它会默认调用ClassLoader.loadClass(name,false),第二个参数为false,因此通过loadClass加载类的时候并不对该类进行解释,不会初始化该类,而Class类的forName方法则相反,会将Class进行解释和初始化。
  • 相关阅读:
    BZOJ.1468.Tree(点分治)
    BZOJ.1935.[SHOI2007]Tree园丁的烦恼(CDQ分治 三维偏序)
    BZOJ.4319.[cerc2008]Suffix reconstruction(后缀数组 构造 贪心)
    BZOJ.3262.陌上花开([模板]CDQ分治 三维偏序)
    洛谷.3374.[模板]树状数组1(CDQ分治)
    BZOJ.4566.[HAOI2016]找相同字符(后缀数组 单调栈)
    POJ.3145.Common Substrings(后缀数组 倍增 单调栈)
    POJ.2774.Long Long Message/SPOJ.1811.LCS(后缀数组 倍增)
    POJ.1743.Musical Theme(后缀数组 倍增 二分 / 后缀自动机)
    UOJ.35.[模板]后缀排序(后缀数组 倍增)
  • 原文地址:https://www.cnblogs.com/qianye/p/2786340.html
Copyright © 2011-2022 走看看