类装载器

类装载器验证流程

1、加载

    取得类的二进制流

    转化为方法区的数据结构

    在java堆中生成对应的 java.lang.Class对象

2、链接   

      验证

             目的:保证Class流的格式是否正确

             文件格式是否正确、元数据验证、字节码验证、符号引用验证

      准备

            分配内存,并为类设置初始值(在方法区中)

     public static int v=1;
         在准备阶段中,v会被设置为0
    在初始化的<clinit>中才会被设置为1
    对于static final类型,在准备阶段就会被赋上正确的值
    public static final  int v=1;

      解析

           符号引用替换为直接引用

            符号引用 :字符串   引用对象不一定被加载
            直接引用:指针或者地址偏移量    引用对象一定在内存

3、初始化

        执行类的构造器<clinit>   :static 变量赋值    static{}语句

        子类的<clinit> 调用前,保证父类的    <clinit>被调用

        <clinit>是线程安全的      

什么是类装载器ClassLoader

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)
  寻找已经加载的类

 

JDK中ClassLoader 默认的设计模式

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文件,进行动态编译,不需要停止。

原文地址:https://www.cnblogs.com/lizhiyan-world/p/7326544.html