时间:2021-05-20
基本概念:类加载的过程大致分为三个阶段
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实际的跟着代码走一遍,看看控制台的输出,用自己的思路虚拟着跟一跟,对于类的加载过程能够认识的更加清晰一些。
以上这篇JVM 心得分享(加载 链接 初始化)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
系统可能在第一次使用某个类时加载该类,也可能采用预加载机制来加载某个类。本节将会详细介绍类加载、连接和初始化过程中的每个细节。JVM和类当调用java命令运行某
jquery和js初始化加载页面的区别:jquery:等待页面加载完数据,以及页面部分元素(不包括图片、视频),js:是页面全部加载完成才执行初始化加载。1、j
本文实例讲述了sogou地图API应用,是非常实用的技巧。分享给大家供大家参考。具体实现方法如下:地图的初始化1、添加引用地图的API文件:2、网站初始化加载事
在Java程序中,有时候可能需要推迟一些高开销的对象初始化操作,并且只有在使用这些对象时才进行初始化。这称为延迟初始化或懒加载看一个不安全的延迟初始化:A线程执
1.初始化顺序 当Java创建一个对象时,系统先为该对象的所有实例属性分配内存(前提是该类已经被加载过了),接着程序开始对这些实例属性执行初始化,其初始化顺序