初步了解Java的类加载机制
2021/9/13 22:05:20
本文主要是介绍初步了解Java的类加载机制,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Java运行时一个类是什么时候开始被加载的?
《java虚拟机规范》中并没有进行强制约束,交给了虚拟机自己去自由实现,HotSpot虚拟机是按需加载,在需要用到该类的时候加载这个类
1.Sun公司最早的Classic虚拟机
2.Sun/Oracle公司的HotSpot虚拟机
3.BEA公司的JRockit虚拟机
4.IBM公司的IBM J9虚拟机
https://docs.oracle.com/javase/8/docs/
JVM一个类的加载过程?
一个类从加载到jvm内存,到从jvm内存卸载,它的整个生命周期会经历7个阶段:
1、加载( Loading)
2、验证( Verification)
3、准备( Preparation)
4、解析( Resolution)
5、初始化( Initialization)
6、使用( Using)
7、卸载( Unloading)
其中验证、准备、解析三个阶段统称为链接( Linking)
类加载生命周期
加载: classpath、jar包、网络、某个磁盘位置下的类的dass二进制字节流读进来,在内存中生成一个代表这个类的 java.lang.Class对象放入堆上,class字节码二进制数据是放在元空间上,此阶段我们程序员可以干预,我们可以自定义类加载器来实现类的加载 -----------------------------------链接------------------------------------- 验证: 验证 Class文件的字节流中包含的信息符合《Java虚拟机规范》的全部约束要求,保证虚拟机的安全; 准备: 类变量赋默认初始值,int为0,long为0L, boolean为 false,引用类型为null,常量赋正式值 解析: 把符号引用翻译为直接引用 ---------------------------------------------------------------------------- 初始化: 当我们new一个类的对象,访问一个类的静态属性,修改一个类的静态属性,调用一个类的静态方法,用反射API对一个类进行调用,初始化当前类,其父类也会被初始化.那么这些都会触发类的初始化; 使用: 使用这个类 卸载:(其实很少会卸载类) 1.该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例 2.加载该类的Classloader已经被GC; 3.该类的 java.lang.Class对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法;
public class Test { // 常量,准备阶段 a 就赋值为123 public static final int a = 123; // 静态类变量,准备阶段时b赋初始值为0 ,初始化阶段时赋值为234 public static int b = 234; // 实例变量 ,准备阶段不处理,创建对象时赋值 public int c = 789; //静态初始化块 初始化阶段执行 static { System.out.println("=============静态初始化块==============="); System.out.println("现阶段输出各种变量为: " + a + "," + b); System.out.println("======================================"); } //初始化块 创建对象的时候执行 { System.out.println("---------初始化块-----------------------"); System.out.println("现阶段输出各种变量为: " + a + "," + b + "," + c); System.out.println("---------------------------------------"); } //构造器 创建对象的时候执行 public Test(){ System.out.println("+++++++++++++构造器(构造函数)+++++++++++++"); System.out.println("现阶段输出各种变量为: " + a + "," + b + "," + c); System.out.println("+++++++++++++++++++++++++++++++++++++++++"); } public static void main(String[] args) { // -XX:+TraceClassLoading (vm参数,用于监控类加载) new Test(); } }
一个类被初始化的过程
类的初始化阶段,Java虚拟机才真正开始执行类中编写的Java程序代码;进行准备阶段时,变量已经赋过一次系统要求的初始零值,而在初始化阶段,才真正初始化类变量和其他资源( 准备阶段:赋予变量初始化值 --> 初始化阶段:赋予变量真正的值)
继承时父子类的初始化顺序是怎样的?
案例代码:
public class ParentClass { //静态变量 public static String p_StaticField = "父类--静态变量"; //变量 public String p_Field = "父类--变量"; //静态初始化快 static { System.out.println(p_StaticField); System.out.println("父类--静态初始化块"); } //初始化块 { System.out.println(p_Field); System.out.println("父类-初始化块"); } public ParentClass() { System.out.println("父类--构造器"); } public static void main(String[] args) { //new ParentClass(); } } //------------------------------------------------------------------------------------------------------- public class SonClass extends ParentClass { //静态变量 public static String s_StaticField = "子类--静态变量"; //变量 public String s_Field = "子类--变量"; //静态初始化快 static { System.out.println(s_StaticField); System.out.println("子类--静态初始化块"); } //初始化块 { System.out.println(s_Field); System.out.println("子类--初始化块"); } public SonClass() { System.out.println("子类--构造器"); } public static void main(String[] args) { //new ParentClass(); /* 父类--静态变量 父类--静态初始化块 子类--静态变量 子类--静态初始化块 父类--变量 父类-初始化块 父类--构造器 */ new SonClass(); /* 父类--静态变量 父类--静态初始化块 子类--静态变量 子类--静态初始化块 父类--变量 父类-初始化块 父类--构造器 子类--变量 子类--初始化块 子类--构造器 */ } }
根据代码结果可知:
先加载父类静态变量以及静态初始块,然后是子类静态变量以及静态初始块,然后根据具体情况先加载父类变量以及初始化块,再加载子类变量以及初始化块
究竟什么是类加载器?
在类加载阶段,通过—个类的全限定名来获取描述该类的二进制字节流的这个动作的“代码”被称为“类加载器”( Class loader),这个动作是可以自定义实现的; 所以 类加载器其实也是程序代码
JVM有哪些类加载器?
站在Java虚拟机的角度来看,只存在两种不同的类加载器
1、启动类加载器( Bootstrap Classloader),使用C++语言实现,是虚拟机自身的部分
2、其他所有的类加载器,由Java语言实现,独立存在于虚拟机外部,并且大部分都继承自抽象类 java.lang.Classloader(父委派模式是通过组合来实现的)
站在Java开发者的角度来看,自JDK1.2开始,Java一直保持着三层类加载器架构;
JVM中不同的类加载器加载哪些文件?
1、启动类加载器( Bootstrap ClassLoader)---------根的类加载器
<JAVA_HOME>\jre\lib目录下的 rt.jar 、resources.jar、 charsets. jar 被-Xbootclasspath参数所指定的路径中存放的类库
public class ClassLoader01 { public static void main(String[] args) { // 都是jre\lib目录下类,但是并不是所有类都通过BootstrapClassLoader加载 System.out.println(HKSCS.class.getClassLoader());//BootstrapClassLoader->null System.out.println(BufferedInputStream.class.getClassLoader());//BootstrapClassLoader->null System.out.println(DefaultHandler.class.getClassLoader());//BootstrapClassLoader->null System.out.println(AppInitEvent.class.getClassLoader());//AppClassLoader /* (注意:底层是由c++写的,通过BootstrapClassLoader加载 结果为null) null null null sun.misc.Launcher$AppClassLoader@18b4aac2 */ } }
2、扩展类加载器( Extension ClassLoader)
sun. misc. Launcher$ExtClassLoader
<JAVA_HOME>\jre\lib\ext , 被java.ext.dirs系统变量所指定的路径中所有的类库
3、应用程序类加载器( Application ClassLoader)---------系统的类加载器
sun. misc. Launcher$AppClassloader ,加载用户类路径( ClassPath)上所有的类库;
这篇关于初步了解Java的类加载机制的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-28MQ底层原理资料详解:新手入门教程
- 2024-11-28MQ项目开发资料详解:新手入门教程
- 2024-11-28MQ项目开发资料详解:入门与初级用户指南
- 2024-11-28MQ消息队列资料入门教程
- 2024-11-28MQ消息队列资料:新手入门详解
- 2024-11-28MQ消息中间件资料详解与应用教程
- 2024-11-28MQ消息中间件资料入门教程
- 2024-11-28MQ源码资料详解与入门教程
- 2024-11-28MQ源码资料入门教程
- 2024-11-28RocketMQ底层原理资料详解