一 类加载机制

 

一、类加载顺序:

  1、加载

      加载二进制字节流,在内存中生成java.lang.class对象,二进制字节流可以从多个方面获取,如 网络 、数据库、zip等

  2、验证

      确保class字节流是满足虚拟机规范,并不会威胁虚拟机自身安全 这个阶段包括文件格式验证(比如 魔数 版本等),元数据验证 字节码验证   

  3、准备

      正式为类变量分配内存并设置类变量初始值的阶段,这些变量使用的内存都将在方法区中进行分配,这里进行的内存分配只包括被static修饰的变量,(实例变量将在类实例化后分配内存),在准备阶段只进行初始化并不进行赋值(比如 static int a =123准备阶段初始值为0,而不是123),被final修饰的除外

    

  4、解析

      虚拟机将常量池中的符号引用变成直接引用的过程 

  5、初始化

      执行类中定义的JAVA 代码,如:static代码块 static修饰的变量赋值 在以下几中情况下会进行类的初始化(初始化之前的几个阶段是必须新进行的 )

    a、遇到 new getstatic putstatic invokestatic 这四条字节码指令时,如果类没有进行初始化需要先触发初始化

    b、使用反射包的方法对类进行反射调用时,如果类没有初始化需要先触发其初始化

    c、初始化一个类时如果其父类还没进行初始化

    d、虚拟机启动时指定的main的类如果没有初始化需要触发初始化

    e、动态语言支持,如果一个java.lang.invoke.MethodHandle实例最后解析结果REF-getStatic ,REF-putStatic,REF-invokeStatic的方法句柄所对应的类没有初始化 需要将其初始化

  6、使用

    

  7、卸载

 

  其中加载 验证 准备 初始化 卸载 这五个阶段顺序确定,必须按照这种顺序按部就班的开始,解析在某些情况下可以在初始化之后进行

  

二、类加载器    

  1、  类加载器模型: 双亲委派

       BootStapClassLoader  <-- ExtensionClassLoader <-- ApplicationClassLoader <-- UserClassLoader

  2、  双亲委派模型的

    优点 : 

      a、安全

        为啥安全 如系统库中的class只能被顶级类加载器(BootStrapClassLoder)加载,这样就避免了用户自己如果写了危害系统的和系统库相同名称的类 加载后危害系统

      b、防止一个类多次加载

        一个类可能从zip war 或者网络而来。防止混乱

    缺点 :

      a、效率较低  每次都得往上找父加载器,找不到父加载器才会用自己的加载器

  3、打破双亲委派模型

      a、使用线程上下文类加载器(setContentClassLoder)修改 

package review.thread.lock;

public class TestClassLoder {
    public static void main(String[] args) {
        Thread thread = Thread.currentThread() ;
        ClassLoader loder =  thread.getContextClassLoader();
        System.out.println(loder.toString());

        thread.setContextClassLoader(new MyClassLoader());
        loder = thread.getContextClassLoader();
        System.out.println(loder);
        
    }

}

  

    b、复写loadeCLass

       loadeClass方法就是先找父找不到再找子,再找不到才会用自己的类加载器,通过修改里面的逻辑就可以使用自己的加载器,

        比方说简单的代码加密会修改class文件的字节就行修改,就可以通过loadeClass进行解密前提是你知道加密规则

 

 

    自定义类加载器 : 建议实现findClass()方法    

  

 

      

posted @ 2020-04-15 11:13  王南辉  阅读(90)  评论(0)    收藏  举报