取得类的二进制流java
转化为方法区的数据结构设计模式
在java堆中生成对应的 java.lang.Class对象缓存
验证安全
目的:保证Class流的格式是否正确数据结构
文件格式是否正确、元数据验证、字节码验证、符号引用验证ide
准备spa
分配内存,并为类设置初始值(在方法区中)线程
public static int v=1;
在准备阶段中,v会被设置为0
在初始化的<clinit>中才会被设置为1
对于static final类型,在准备阶段就会被赋上正确的值
public static final int v=1;设计
解析3d
符号引用替换为直接引用
符号引用 :字符串 引用对象不必定被加载
直接引用:指针或者地址偏移量 引用对象必定在内存
执行类的构造器<clinit> :static 变量赋值 static{}语句
子类的<clinit> 调用前,保证父类的 <clinit>被调用
<clinit>是线程安全的
ClassLoader 是一个抽象类
ClassLoader的实例将读入java字节码类装载到JVM
ClassLoader能够定制,知足不通字节码流获取的方式
ClassLoader负责类加载过程的加载阶段
public Class<?> loadClass(String name) throws ClassNotFoundException
载入并返回一个Class
protected final Class<?> defineClass(byte[] b, int off, int len)
定义一个类,不公开调用
protected Class<?> findClass(String name) throws ClassNotFoundException
loadClass回调该方法,自定义ClassLoader的推荐作法
protected final Class<?> findLoadedClass(String name)
寻找已经加载的类
BootStrap ClassLoader (启动ClassLoader) 这个父类 没有 ClassLoader
Extension ClassLoader (扩展ClassLoader)
App ClassLoader (应用ClassLoader/系统ClassLoader)
Custom ClassLoader(自定义ClassLoader)
Java中ClassLoader的加载采用了双亲委托机制,采用双亲委托机制加载类的时候采用以下的几个步骤:
1. 当前ClassLoader首先从本身已经加载的类中查询是否此类已经加载,若是已经加载则直接返回原来已经加载的类。
每一个类加载器都有本身的加载缓存,当一个类被加载了之后就会放入缓存,等下次加载的时候就能够直接返回了。
2. 当前classLoader的缓存中没有找到被加载的类的时候,委托父类加载器去加载,父类加载器采用一样的策略,首先查看本身的缓存,而后委托父类的父类去加载,一直到bootstrp ClassLoader.
3. 当全部的父类加载器都没有加载的时候,再由当前的类加载器加载,并将其放入它本身的缓存中,以便下次有加载请求的时候直接返回。
说到这里你们可能会想,Java为何要采用这样的委托机制?理解这个问题,咱们引入另一个关于Classloader的概念“命名空间”, 它是指要肯定某一个类,须要类的全限定名以及加载此类的ClassLoader来共同肯定。也就是说即便两个类的全限定名是相同的,可是由于不一样的ClassLoader加载了此类,那么在JVM中它是不一样的类。明白了命名空间之后,咱们再来看看委托模型。采用了委托模型之后加大了不一样的 ClassLoader的交互能力,好比上面说的,咱们JDK本生提供的类库,好比hashmap,linkedlist等等,这些类由bootstrp 类加载器加载了之后,不管你程序中有多少个类加载器,那么这些类其实都是能够共享的,这样就避免了不一样的类加载器加载了一样名字的不一样类之后形成混乱。
Java除了上面所说的默认提供的classloader之外,它还允许应用程序能够自定义classloader,那么要想自定义classloader咱们须要经过继承java.lang.ClassLoader来实现,
这里咱们须要注意一点就是public Class<?>loadClass(String name) throws ClassNotFoundException没有被标记为final,也就意味着咱们是能够override这个方法的,也就是说双亲委托机制是能够打破的。
在应用工做的时候,进行修改java文件,进行动态编译,不须要中止。