补充(非书中):

  Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取Java字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。

Java 中的类加载器大致可以分成两类:

一类是系统提供的:

  • 引导类加载器(bootstrapclass loader):它用来加载 Java 的核心库,是用原生代码而不是java来实现的,并不继承自java.lang.ClassLoader,除此之外基本上所有的类加载器都是java.lang.ClassLoader类的一个实例。
  • 扩展类加载器(extensionsclass loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录(一般为%JRE_HOME%/lib/ext)。该类加载器在此目录里面查找并加载 Java 类。
  • 系统类加载器(systemclass loader或 App class loader):它根据当前Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader() 来获取它。

另外一类则是由 Java 应用开发人员编写的:

  • 开发人员可以通过继承java.lang.ClassLoader 类的方式实现自己的类加载器,以满足一些特殊的需求

 classLoader是类加载器,负责将Class加载到JVM中,还有一个作用是审查每个类由谁加载,它是一种父优先的等级加载机制。

还有一个任务是,将class字节码重新解析成JVM统一要求的对象格式。

加载类过程:

  假如loader2的parent为loader1,loader1的parent为system class loader。假设loader2被要求装载类MyClass,在parent delegation模型下,loader2首先请求loader1代为装载,loader1再请求系统类装载器去装载MyClass。若系统装载器能成功装载,则将MyClass所对应的Class对象的reference返回给loader1,loader1再将reference返回给loader2,从而成功将类MyClass装载进虚拟机。若系统类装载器不能装载MyClass,loader1会尝试装载MyClass,若loader1也不能成功装载,loader2会尝试装载。若所有的parent及loader2本身都不能装载,则装载失败。

6.1 ClassLoader类结构分析

 defineClass(byte[], int, int): 将byte字节流解析成JVM能识别的class对象。

 findClass(String):

 loadClass(String): 获取class对象。

 resolveClass(Class<?>):

ClassLoader是抽象类,有很多子类,如果我们要实现自己的ClassLoader,一般会继承URLClassLoader, 做修改就好了。

6.2 ClassLoader的等级加载机制

JVM提供三层ClassLoader,这三层ClassLoader可以分为两种类型

(1)Bootstrap ClassLoader: 加载JVM自身工作需要的类,完全由JVM自己控制,别人访问不到这个类,没有高一级的加载器,也没有子加载器。

(2)ExtClassLoader:

(3)AppClassLoader:

如果我们要实现自己的类加载器,不管是直接实现抽象类ClassLoader,还是继承URLClassLoader,或其他子类,它的父加载器都是AppClassLoader。

ExtClassLoader和AppClassLoader都继承了URLClassLoader类。

  

JVM加载class文件到内存有两种方式:

隐式加载:不在代码中调用ClassLoader来加载需要的类,而是通过JVM来自动加载需要的类到内存的方式。比如当在类中继承或引用某个类时,JVM发现其不在内存中,就会自动加载到内存。

显示加载:通过ClassLoader类来加载一个类的方式,this.getClass.getClassLoader().loadClass()或者Class.forName(). 或者我们自己实现的ClassLoader的findClass()方法。

6.3 如何加载class文件

       三个步骤:

    1 找到.class文件并把这个文件包含的字节码加载到内存。

2 字节码校验,Class类数据结构分析以及相应的内存分配和最后的符号表链接

    3 类中静态属性和初始化赋值,已经静态块的执行等。  

  6.3.1 加载字节码到内存

    URLClassLoader如何实现findclass()的,URLCclassLoader中通过一个URLClassPath类帮助取得要加载的class文件字节流,而这个URLClasspath定义了到哪里去找这个

    class文件,如果找到,再读它的byte字节流,通过definClass()来创建类对象。根据路径的不同(是文件还是jar包)来创建FIleLoader或JarLoader.

  6.3.2 验证与解析

    字节码验证,验证格式正确,行为正确。

    类准备,这个阶段准备代表每个类中定义的字段,方法和实现接口所必须的数据结构。

    解析,装入类所引用的其他所有类。

  6.3.3 初始化class对象

    执行静态初始化器,静态字段会为初始化为默认值。

6.4 常见加载类错误分析

    6.4.1 ClassNotFoundException

  显示加载类三种方法:

    Class.forName();

    ClassLoader.loadClass()

    ClassLoader.findSystemClass()   

  6.4.2 NoClassDefFoundError

    类可能没加包名。

  6.4.3 UnsatisfiedLinkError

    可能是误删了lib文件

  6.4.4 ClassCastExcetption

    JVM做类型转换的检查规则:

  • 普通对象,对象必须是目标类的实例或是目标类子类的实例。如果目标类是接口,那么可以把它当做实现了该接口的一个子类。
  •  对于数组类型,目标类型必须是数组类型或java.lang,Object, java.lang,Clonble, java.io.serializable

如果不满足上面的规则,JVM就会报错:

要想避免这个错误 有两种方式:

      容器类型中显示地指明容器对象类型,

      通过instanceof检查是不是目标类型,然后在强转。

  6.4.5 ExceptinInInitializerError

6.5 常用的ClassLoader分析

  这里分析了servlet的ClassLoader

6.6 如何实现自己的ClassLoader

  为什么要实现自己的classLoader

    在自己的路径下查找自定义的class文件,不一定在classPath下面。

    对我们的类做特殊处理,比如加密传输类在网络之间。这就需要在加载到JVM之前先解密。

    可以定义类的实现机制,实现热部署。

  6.6.1 加载自定义路径下的class文件

  6.6.2 加载自定义格式的class文件

6.7 实现类的热部署

  JVM在加载类之前会检查类是否已经被加载过,也就是要调用findLoadedClass()方法查看是否能返回类实例

JVM表示两个类是否是同一个类有两个条件:

    一是看类的完整类名是否一样。

    二是看加载这个类的ClassLoader是否是同一个(是指ClassLoader实例是否是同一个)。

实现热部署:可以用ClassLoader的两个实例加载同名的类。

6.8 java应不应该动态加载类

  JAVA修改一个类,必须重启JVM。

第六章 深入分析ClassLoader工作机制的更多相关文章

  1. 《精通Spring4.X企业应用开发实战》读后感第六章(内部工作机制、BeanDefinition、InstantiationStrategy、BeanWrapper)

  2. 深入理解ClassLoader工作机制(jdk1.8)

    ClassLoader 顾名思义就是类加载器,ClassLoader 作用: 负责将 Class 加载到 JVM 中    审查每个类由谁加载(父优先的等级加载机制)    将 Class 字节码重新 ...

  3. Android群英传笔记——第六章:Android绘图机制与处理技巧

    Android群英传笔记--第六章:Android绘图机制与处理技巧 一直在情调,时间都是可以自己调节的,不然世界上哪有这么多牛X的人 今天就开始读第六章了,算日子也刚好一个月了,一个月就读一半,这效 ...

  4. 理解ClassLoader工作机制

    package com.ioc; public class Test { public static void main(String[] args) throws ClassNotFoundExce ...

  5. Java Web 深入分析(5) Java ClassLoader 工作机制

    Classloader 有3个作用 将class加载到JVM中去 审查每个类由谁去加载,是一种父优先的等级加载 把Class字节码统一编译成JVM统一要求的对象格式 ClassLoader的等级加载机 ...

  6. ClassLoader工作机制

    阅读目录 一.ClassLoader概念 二.JVM平台提供三层classLoader 三.JVM加载class文件到内存有两种方式 四.ClassLoader加载类的过程 五.自定义类加载器 六.实 ...

  7. Java Web ClassLoader工作机制

    一.ClassLoader的作用: 1.类加载机制:父优先的等级加载机制 2.类加载过程 3.将Class字节码重新解析成JVM统一要求的对象格式 二.ClassLoader常用方法 1.define ...

  8. ClassLoader 工作机制

    ClassLoader 采用上级委托接待机制加载 class JVM 平台提供三层 ClassLoader 1.Bootstrap ClassLoader:主要加载 JVM 自身工作需要的类 2.Ex ...

  9. 第2章 深入分析java I/O的工作机制(上)

    java的I/O操作类在包java.io下,大致分成4组: 所有文件的存储都是字节(byte)的储存,在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再存储这些字节到磁盘.在读取文件时,也是一个 ...

随机推荐

  1. Mongodb笔记(二) Index

    版本:mongodb3.4; Index  : 如果mongodb不能使用索引进行排序,就会将数据放入内存中进行排序,而当内存使用超过32MB时,就会报错. 在创建索引时,应确保索引的选择力,避免多余 ...

  2. spring3: AOP 之代理机制

    Spring AOP通过代理模式实现,目前支持两种代理:JDK动态代理.CGLIB代理来创建AOP代理,Spring建议优先使用JDK动态代理. JDK动态代理:使用java.lang.reflect ...

  3. IE兼容性测试工具IETester

    IE兼容性测试工具:IETester 1.这种做法,不能做到100%的覆盖: 2.实际的业务场景会比IEtester更符合.

  4. laravel支持的日志写入模式和日志严重程度级别:

    四种日志写入模式: single:单一的 daily:日常的 syslog:系统记录 errorlog:错误日志 Monolog 识别以下严重程度的级别, 从低到高为: debug. info.not ...

  5. 【51nod-1046】最大子矩阵和

    一个M*N的矩阵,找到此矩阵的一个子矩阵,并且这个子矩阵的元素的和是最大的,输出这个最大的值.   例如:3*3的矩阵:   -1 3 -1 2 -1 3 -3 1 2   和最大的子矩阵是:   3 ...

  6. Makefile的补充学习

    通配符%和Makefile自动推导(规则)(1)%是Makefile中的通配符,代表一个或几个字母.也就是说%.o就代表所有以.o为结尾的文件.(2)所谓自动推导其实就是Makefile的规则.当Ma ...

  7. 内存保护机制及绕过方案——利用未启用SafeSEH模块绕过SafeSEH

    前言:之前关于safeSEH保护机制的原理等信息,可在之前的博文(内存保护机制及绕过方案中查看). 利用未启用SafeSEH模块绕过SafeSEH ⑴.  原理分析: 一个不是仅包含中间语言(1L)且 ...

  8. 记录下httpclient 发送请求 服务端用@RequestBody 自动接收参数 报415

    注解是post方式,那么检查以下内容:1. 你是否用了post请求2. 请求是否发送了数据3. 请求内容格式需要是 application/json .jquery 设置 contentType,-- ...

  9. POJ 2954 Triangle (pick 定理)

    题目大意:给出三个点的坐标,问在这三个点坐标里面的整数坐标点有多少个(不包含边上的) 匹克定理:I = (A-E) / 2 + 1; A: 表示多边形面积 I : 表示多边形内部的点的个数 E: 表示 ...

  10. python学习之基本类型

    #我的第一个python程序 print("hello world"); #多行字符串 print("""\ Usage: thingy [OPTIO ...