Java 类的加载过程 类初始化分析 类加载器 ゝ一世哀愁。 2024-03-27 15:41 20阅读 0赞 ### 类的加载过程 ### ![在这里插入图片描述][3faed0ecfbb04fb5bccefe651bfe8d46.png] 图片来自狂神说java:[类加载内存分析][Link 1] ### 类的加载与ClassLoader的理解 ### * 加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象. * 链接:将Java类的二进制代码合并到JVM的运行状态之中的过程。 * 验证: 确保加载的类信息符合JVM规范,没有安全方面的问题 * 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配。 * 解析: 虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。 * 初始化: * 执行类构造器"<“clinit”>"()方法的过程。类构造器"<“clinit”>"()方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)。 * 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。 * 虚拟机会保证一个类的"<“clinit”>"()方法在多线程环境中被正确加锁和同步。 1. 加载到内存,会产生一个类对应的Class对象 2. 链接,链接结束后 m = 0 3. 初始化 <clinit>(){ System.out.println("A类静态代码块初始化"): m = 300; m = 100; } package com.reflection; public class Test04 { public static void main(String[] args) { A a = new A(); System.out.println(A.m); } } class A{ static { System.out.println("A类的静态代码块初始化"); m = 300; } static int m = 100; public A(){ System.out.println("A类的无参构造初始化"); } } #### 什么时候会发生类的初始化? #### * 类的主动引用(一定会发生类的初始化) * 当虚拟机启动,先初始化main方法所在的类 * new一个类的对象 * 调用类的静态成员(除了final常量)和静态方法 * 使用java.lang.reflect包的方法对类进行反射调用 * 当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类 * 类的被动引用(不会发生类的初始化) * 当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化 * 通过数组定义类引用,不会触发此类的初始化 * 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了) package com.reflection; //测试类什么时候回初始化 public class Text06 { static { System.out.println("main类被加载"); } public static void main(String[] args) throws ClassNotFoundException { //1. 主动引用 //Son son = new Son(); //反射,也会产生主动引用 //Class.forName("com.reflection.Son"); //不会产生类的引用的方法: //b是父类的,子类不会被加载,只会加载父类 System.out.println(Son.b); //只会创建一个空间,并不会加载类 Son[] array = new Son[5]; //M只是一个常量,常量在链接阶段就已经存入常量池了 System.out.println(Son.M); } } class Father{ static { System.out.println("父类被加载"); } static int b = 2; } class Son extends Father{ static { System.out.println("子类被加载"); m = 300; } static int m = 100; static final int M = 1; } #### 类加载器的作用 #### * 类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。 * 类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象 ![在这里插入图片描述][1ed2d47a723a4d81948858765f7513cc.png] #### 类加载器作用是用来把类(class)装载进内存的。 #### ![在这里插入图片描述][8f27ea510ed642eaaba4663b4122385f.png] ##### JVM 规范定义了如下类型的加载器: ##### * 引导类加载器:用C++编写的,是JVM自带的类加载器,负责Java平台核心库,用来装载核心类库。**该加载器无法直接获取** * 扩展类加载器:负责jre/lib/ext目录下的jar包或-D java.ext.dirs指定目录下的jar包装入工作库 * 系统类加载器:负责java-classpath或-D java.class.path所指的目录下的类与jar包装入工作,是最常用的加载器 package com.reflection; public class Test07 { public static void main(String[] args) throws ClassNotFoundException { //获取系统类的加载器 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2 //获得系统类加载器的父类加载器-->扩展类加载器 ClassLoader parent = systemClassLoader.getParent(); System.out.println(parent);//sun.misc.Launcher$ExtClassLoader@1b6d3586 //获取扩展类加载器的父类加载器-->跟加载器(C/C++) ClassLoader parent1 = parent.getParent(); System.out.println(parent1);//null //测试当前类,是哪个加载器加载的 ClassLoader classLoader = Class.forName("com.reflection.Test07").getClassLoader(); System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2 //测试jdk 内置的类,是哪个加载器加载的 classLoader = Class.forName("java.lang.Object").getClassLoader(); System.out.println(classLoader);//null 跟加载器加载的 //如何获得系统类加载器--可以加载的路径 System.out.println(System.getProperty("java.class.path")); /*D:\environment\java\jdk1.8\jre\lib\charsets.jar;D:\environment\java\jdk1.8\jre\lib\deploy.jar; D:\environment\java\jdk1.8\jre\lib\ext\access-bridge-64.jar; D:\environment\java\jdk1.8\jre\lib\ext\cldrdata.jar; D:\environment\java\jdk1.8\jre\lib\ext\dnsns.jar; D:\environment\java\jdk1.8\jre\lib\ext\jaccess.jar; D:\environment\java\jdk1.8\jre\lib\ext\jfxrt.jar; D:\environment\java\jdk1.8\jre\lib\ext\localedata.jar; D:\environment\java\jdk1.8\jre\lib\ext\nashorn.jar; D:\environment\java\jdk1.8\jre\lib\ext\sunec.jar; D:\environment\java\jdk1.8\jre\lib\ext\sunjce_provider.jar; D:\environment\java\jdk1.8\jre\lib\ext\sunmscapi.jar; D:\environment\java\jdk1.8\jre\lib\ext\sunpkcs11.jar; D:\environment\java\jdk1.8\jre\lib\ext\zipfs.jar; D:\environment\java\jdk1.8\jre\lib\javaws.jar; D:\environment\java\jdk1.8\jre\lib\jce.jar; D:\environment\java\jdk1.8\jre\lib\jfr.jar; D:\environment\java\jdk1.8\jre\lib\jfxswt.jar; D:\environment\java\jdk1.8\jre\lib\jsse.jar; D:\environment\java\jdk1.8\jre\lib\management-agent.jar; D:\environment\java\jdk1.8\jre\lib\plugin.jar; D:\environment\java\jdk1.8\jre\lib\resources.jar; D:\environment\java\jdk1.8\jre\lib\rt.jar; D:\JavaSE\out\production\basic; D:\Program Files\IntelliJ IDEA Community Edition 2022.3.2\lib\idea_rt.jar */ //双亲委派机制 :总的来说就是,假如自己定义了一个系统本来就存在的包,那么这个包是不能运行的(为了保证安全性) //java.lang.String--> } } * **双亲委派机制** :总的来说就是,假如自己定义了一个系统本来就存在的包,那么这个包是不能运行的(为了保证安全性) [3faed0ecfbb04fb5bccefe651bfe8d46.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/27/c833ec889bb54a53b423e6f361e22c5f.png [Link 1]: https://www.bilibili.com/video/BV1p4411P7V3?p=9&vd_source=9c780beab5c2c91cdd382d86fbccb668 [1ed2d47a723a4d81948858765f7513cc.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/27/b1bef872ccb147c7aa91e72c047de409.png [8f27ea510ed642eaaba4663b4122385f.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/27/eb3fbd6451bb43b5971b3d98bf8437d0.png
还没有评论,来说两句吧...