黑马程序员系列第九篇 类加载器

ASP.Net+Android+IOS开发  、Net培训、期待与您交流!

推荐阅读相关书籍《深入java虚拟机》

目录:1、java.lang.ClassLoader类介绍      2、类加载器的结构     3、加载类的过程     4、自定义类加载器

类加载器负责加载 Java 类的字节代码到 Java 虚拟机中。

类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一。它使得 Java 类可以被动态加载到 Java 虚拟机中并执行。

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

基本上所有的类加载器都是 java.lang.ClassLoader类的一个实例。

1、java.lang.ClassLoader类介绍

java.lang.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个 Java 类,即 java.lang.Class类的一个实例。

2、类加载器的结构

Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的。系统提供的类加载器主要有下面三个:

  • 引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自 java.lang.ClassLoader
  • 扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
  • 系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。

除了系统提供的类加载器以外,开发人员可以通过继承 java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求。

验证此结构的代码

 1  public class ClassLoaderTree {
 2
 3     public static void main(String[] args) { //创建类加载器
 4         ClassLoader loader = ClassLoaderTree.class.getClassLoader(); //通过while循环,打印父类类加载
 5         while (loader != null) {
 6             System.out.println(loader.toString());
 7             loader = loader.getParent();
 8         }
 9     }
10  }

Java 虚拟机是如何判定两个 Java 类是相同的:

Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。

3、加载类的过程

在前面介绍类加载器的代理模式的时候,提到过类加载器会首先代理给其它类加载器来尝试加载某个类。这就意味着真正完成类的加载工作的类加载器和启动这个加载过程的类加载器,有可能不是同一个。真正完成类的加载工作是通过调用 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类的实例缓存起来。下次再请求加载该类的时候,类加载器会直接使用缓存的类的实例,而不会尝试再次加载。

4、自定义类加载器

虽然在绝大多数情况下,系统默认提供的类加载器实现已经可以满足需求。但是在某些情况下,您还是需要为应用开发出自己的类加载器。比如您的应用通过网络来传输 Java 类的字节代码,为了保证安全性,这些字节代码经过了加密处理。这个时候您就需要自己的类加载器来从某个网络地址上读取加密后的字节代码,接着进行解密和验证,最后定义出要在 Java 虚拟机中运行的类来。

自定义一个文件系统类加载器代码

 1  public class FileSystemClassLoader extends ClassLoader {
 2
 3     private String rootDir;
 4      //加载器的构造方法
 5     public FileSystemClassLoader(String rootDir) {
 6         this.rootDir = rootDir;
 7     }
 8        //寻找类
 9     protected Class<?> findClass(String name) throws ClassNotFoundException {
10         byte[] classData = getClassData(name);
11         if (classData == null) {
12             throw new ClassNotFoundException();
13         }
14         else {
15             return defineClass(name, classData, 0, classData.length);
16         }
17     }
18            //获得类中数据
19     private byte[] getClassData(String className) {
20         String path = classNameToPath(className);
21         try {
22             InputStream ins = new FileInputStream(path);
23             ByteArrayOutputStream baos = new ByteArrayOutputStream();
24             int bufferSize = 4096;
25             byte[] buffer = new byte[bufferSize];
26             int bytesNumRead = 0;
27             while ((bytesNumRead = ins.read(buffer)) != -1) {
28                 baos.write(buffer, 0, bytesNumRead);
29             }
30             return baos.toByteArray();
31         } catch (IOException e) {
32             e.printStackTrace();
33         }
34         return null;
35     }
36           //定义类加载路径
37     private String classNameToPath(String className) {
38         return rootDir + File.separatorChar
39                 + className.replace(‘.‘, File.separatorChar) + ".class";
40     }
41  }

ASP.Net+Android+IOS开发  、Net培训、期待与您交流!

时间: 2024-10-20 10:42:51

黑马程序员系列第九篇 类加载器的相关文章

黑马程序员系列第二篇 多线程(2)

ASP.Net+Android+IOS开发  .Net培训.期待与您交流! (前言:本篇文章主要依据毕向东老师的课程视频整理而成,如要详细学习,请观看毕老师视频  百度网盘链接地址:http://pan.baidu.com/s/1sjQRHDz) 目录:1.线程通信--生产消费者示例(线程通信安全.等待唤醒机制)    2.停止线程.及其会出现的问题.及解决的办法    3.守护线程及几个Thread的方法                   4.工作中线程的常见写法         1.线程通

黑马程序员——基础加强篇

------- android培训.java培训.期待与您交流! ---------- MyEclipse相关知识 Workspace与project 切换工作空间:File---Switch Workspace---Other 一个工作间包含多个工程,切换工作间之后,会影响里面的工程,例如快捷键什么的都要重新配置如果重新配了之后快捷键还没有用就要考虑下那个快捷键是不是冲突了    视图管理与程序调试 可以通过Window---Show View来添加各种透视图. 调试程序的时候可以在代码右边双

黑马程序员——网络编程篇

------- android培训.java培训.期待与您交流! ---------- 概述   1.网络模型        (1).OSI参考模型        (2).TCP/IP参考模型   2.网络通讯要素         (1).IP地址        (2).端口号         (3).传输协议    3.过程        1,找到对方IP. 2,数据要发送到对方指定的应用程序上.为了标识这些应用程序,所以给这些网络应用程序都用数字进行标识. 为了方便称呼这个数据,叫做端口(逻

黑马程序员——Java基础篇之对象归要

1.static关键字 1.1.static可以修饰成员变量,成员方法,还有类(其中这里的类是内部类) 1.2.static修饰的部分会随着类的加载而加载: 加载过程:当JVM执行static修饰的代码时,会在内存的共享区给static部分开辟一个空间,供该类持有,static部分不是某个对象的部分,而是该类共有的,所以当一个函数会被多个对象调用时,最好定义成static,这样比较节省空间. 1.3.静态方法只能访问静态成员 原因:如果静态方法中调用了非静态的变量,那么由于静态方法是随着类的加载

黑马程序员系列第四篇 集合(1)

ASP.Net+Android+IOS开发  .Net培训.期待与您交流! (前言:本篇文章主要依据毕向东老师的课程视频整理而成,如要详细学习,请观看毕老师视频  百度网盘链接地址:http://pan.baidu.com/s/1o6mwDzO 目录:1.集合概述      2.Collection.Iterator接口     3.List接口与其ArrayList.LinkedList.Vector子类 1.集合概述  下图为JDK中集合的框架设计图,我们主要使用的集合为黑色方框中的四种集合

黑马程序员系列第六篇 面向对象基础

ASP.Net+Android+IOS开发  .Net培训.期待与您交流! (前言:本篇文章主要依据毕向东老师的课程视频整理而成,如要详细学习,请观看毕老师视频  百度网盘链接地址:http://pan.baidu.com/s/1mgngVl2) 目录:1.面向对象三大特性    2.类和对象    3.内部类   1.面向对象三大特性    封装.继承.多态 封装 概念:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式. 好处:将变化隔离:便于使用:提高重用性:安全性. 封装原则:将不需要

黑马程序员系列第八篇 IO(2)

ASP.Net+Android+IOS开发  .Net培训.期待与您交流! (前言:本篇文章主要依据毕向东老师的课程视频整理而成,如要详细学习,请观看毕老师视频  百度网盘链接地址:http://pan.baidu.com/s/1mgrkJWW)  目录:1.File类       2.存储对象      3.RandomAccessFile类  1.File类 File类  :将文件或文件夹封装成对象,方便对文件或文件夹的属性信息进行操作 File中Separator 字段是可跨平台的分隔符

黑马程序员-Java多线程篇《四》

                         ------- android培训.java培训.期待与您交流! ---------- 1.线程和进程的概念 1.1.进程(Process):拥有独立的内存空间,每个独立执行的程序称为进程   1.2.线程(Thread):线程是一个程序内部的一条执行路径,Java虚拟机允许应用程序并发地运行多个执行线程   1.3.线程和进程的区别           每个进程都有独立的代码和数据空间(进程上下文),进程间的切换开销大           线程

黑马程序员——类加载器初识

java类加载器就是将生成的字节码加入到内存中. java类加载器也是类,它们是由最原始的类加载器加入到java虚拟机中,然后再由他们加载其他的类,而最原始的类加载器就是BootStrap,他不是Java类,是由C++编写的 在java中有三种类加载器:BootStrap(加载系统类,如System),ExtClassloader(加载lib/ext/里的.jar包),AppClassLoader(加载我们自定义的类) BootStrap是ExtClassLoader的上级,ExtClassLo