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 首先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:worktemp"; 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,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,paramArrayOfByte.length); } } 日志输出如下: class com.chong.studyparalell.demon.DemonThreadDemo 实际的跟着代码走一遍,看看控制台的输出,用自己的思路虚拟着跟一跟,对于类的加载过程能够认识的更加清晰一些。 以上这篇JVM 心得分享(加载 链接 初始化)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持编程小技巧。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |