• JVM--心得(加载 链接 初始化)


    基本概念:类加载的过程大致分为三个阶段
    1.加载阶段:本阶段主要把class的二进制代码加载进入JVM,并且进行常量池(类名,方法名,字段名),方法区(二进制字节码),栈(本地方法栈结构),堆(java.lang.class对象)的设置。
    有三个加载类:Bootstrap ClassLoader,加载jre/lib/下的类;
    Extension ClassLoader:加载jre/lib/ext下的类;
    ApplicationClassLoader:加载classpath下的类(应用程序自己开发的类,如 工程目录/bin/下的.class文件)
    还有一个扩展的加载类,满足应用程序的特殊需求。类的加载时,父亲loader优先执行load动作,父亲load不了时,子类运作。

    2.链接阶段:又分为三个小阶段 校验,准备,解析。
    校验:实施字节码文件的格式,语法等的校验。
    准备:对静态变量申请存储空间,并设置默认的初始值。如:private static int a =2;那么在准备阶段a被设置为0;
    解析:把方法区中的符号指针替换为直接引用。

    3.初始化阶段:对静态变量进行初始化,执行静态块,创建类的实例。上述的a变量在初始化阶段会被设置为2。

    第一步:验证静态变量和静态块的加载+链接(校验,准备,解析)+初始化过程中值的变化。

    ---------------------------------------------------------------------------------

     package com.chong.studyparalell.clazz.loader;

    public class ClassLoaderDemo {
    public static void main(String []args){
    Test test2 = new Test();

    System.out.println("Test2实例化结束"+test2.toString());

    }
    }

    --------------------------------------------------------------------------------------

    package com.chong.studyparalell.clazz.loader;

    public class Test{

    private static Test test1 = new Test();
    private static int a = 2;
    private static int b = 2;

    static {
    System.out.println("【Test类静态块】a=" + a);
    }

    public Test(){

    System.out.println("【Test类构造方法】a=" + a);
    System.out.println("【Test类构造方法】b=" + b);
    System.out.println("【Test类实例】" + this.toString());
    }

    public static Test newInstance(){
    return test1;
    }
    }

    --------------------------------------------------------------------

    log输出如下:
    1 【Test类构造方法】a=0
    2 【Test类构造方法】b=0
    3 【Test类实例】com.chong.studyparalell.clazz.loader.Test@16c1857
    4 【Test类静态块】a=2
    5 【Test类构造方法】a=2
    6 【Test类构造方法】b=2
    7 【Test类实例】com.chong.studyparalell.clazz.loader.Test@1b1fd9c
    8 Test2实例化结束com.chong.studyparalell.clazz.loader.Test@1b1fd9c

    首先Test类在链接阶段(准备阶段),a,b分别被设置默认值0。
    当new Test()执行后,
    1)首先初始化Test类的三个静态变量 test1,a,b。
    初始化test1时,第一次调用构造方法,此时a,b为0。对应日志1,2行。
    实例化test1,日志第3行。
    test1初始化完成后,继续初始化a,b,设为2。
    接着初始化静态块 ,对应日志第4行。
    2)执行Test类的构造方法
    因为a,b已经被初始化为2,所以执行类的构造方法时,会输出a,b 为2。日志第5,6行。
    实例化后输出地址信息,日志第7行。
    3)最终main方法里打出实例工作完成,日志第8行。

     -------------------------------------------------------------

     第二步,加入父类后,进行确认。

    -------------------------------------------------------------

    package com.chong.studyparalell.clazz.loader;

    public class TestBase {

    private static int base_a = 2;
    private static int base_b = 2;

    static {
    System.out.println("【父类静态块】 base_a="+base_a);
    }

    public TestBase(){
    System.out.println("【父类 构造方法】base_a=" + base_a);
    System.out.println("【父类 构造方法】base_b=" + base_b);
    System.out.println("【父类 实例】"+ this.toString());
    }

    }

    ------------------------------------------------------------------

    package com.chong.studyparalell.clazz.loader;

    public class Test extends TestBase{
    内容同第一步;
    }

    ------------------------------------------------------------------

    log输出如下:

     【父类静态块】 base_a=2

    【父类 构造方法】base_a=2

    【父类 构造方法】base_b=2

    【父类 实例】com.chong.studyparalell.clazz.loader.Test@19ab8d

    【Test类构造方法】a=0

    【Test类构造方法】b=0

    【Test类实例】com.chong.studyparalell.clazz.loader.Test@19ab8d

    【Test类静态块】a=2

    【父类 构造方法】base_a=2

    【父类 构造方法】base_b=2

    【父类 实例】com.chong.studyparalell.clazz.loader.Test@14dcfad

    【Test类构造方法】a=2

    【Test类构造方法】b=2

    【Test类实例】com.chong.studyparalell.clazz.loader.Test@14dcfad

    Test2实例化结束com.chong.studyparalell.clazz.loader.Test@14dcfad

    可以发现父类的静态变量,静态块,构造方法首先被初始化。然后子类的静态变量,静态块和构造方法被初始化。

    ------------------------------------------------------------------

    第三步:写一个自定义的类加载器

    ------------------------------------------------------------------

     package com.chong.studyparalell.clazz.loader;


    public class MyClassLoaderPilot {

    public static void main(String[] args) {

    try {
    MyClassLoader classLoader = new MyClassLoader();
    String filename = "com.chong.studyparalell.demon.DemonThreadDemo";

    Object clazz = classLoader.loadCustomizeClass(filename);
    System.out.println(clazz);

    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    }

    ------------------------------------------------------------------

    package com.chong.studyparalell.clazz.loader;

    import java.io.ByteArrayOutputStream;
    import java.io.FileInputStream;
    import java.io.IOException;

    public class MyClassLoader extends ClassLoader {

    private String demoPath = "D:\work\temp\";

    public Class<?> loadCustomizeClass(String filename) throws ClassNotFoundException {

    FileInputStream fis = null;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
    // 1.获取class文件的字节码(二进制数据)
    String[] fileNames = filename.split("\.");
    fis = new FileInputStream(demoPath + fileNames[fileNames.length-1] +".class");
    byte[] bytes = new byte[1024];
    int len = 0;
    while ((len = fis.read(bytes)) != -1) {
    baos.write(bytes, 0, len);
    }

    } catch (Exception e) {
    throw new ClassNotFoundException();
    } finally {
    try {
    fis.close();
    } catch (IOException e) {
    throw new ClassNotFoundException();
    }
    }

    byte[] paramArrayOfByte = baos.toByteArray();
    // 2。把二进制文件定义为class对象返回
    return defineClass(filename, paramArrayOfByte, 0, paramArrayOfByte.length);
    }
    }

    ------------------------------------------------------------------

    日志输出如下:

    class com.chong.studyparalell.demon.DemonThreadDemo

    ------------------------------------------------------------------

    实际的跟着代码走一遍,看看控制台的输出,用自己的思路虚拟着跟一跟,对于类的加载过程能够认识的更加清晰一些。

    参看link:

    http://www.cnblogs.com/ityouknow/p/5603287.html

    http://www.cnblogs.com/xiaoxiaohui2015/p/5838674.html

  • 相关阅读:
    WebAPI跨域问题处理
    WebAPI学习及Swagger使用
    MSMQ消息队列总结
    学习笔记——泛型
    学习笔记——并行编程Parallel
    学习笔记——多线程
    学习笔记——线程 Thread
    springboot,maven依赖引用失败,手动将jar包导入maven本地仓库
    PostgreSQL如何实现MySQL中的group_concat聚集函数(简单的拼接功能)
    mybatis的XML配置文件sql查询中,传入对象参中某个字段为list时,sql编写方式。
  • 原文地址:https://www.cnblogs.com/chongpf/p/7656593.html
Copyright © 2020-2023  润新知