JVM基础篇——类的加载过程

简介: JVM基础篇——类的加载过程

类的加载机制


类的生命周期


类在JVM中的生命周期分七个阶段:加载、验证、准备、解析、初始化、使用和卸载。其中验证、准备、解析有称为类的连接。加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,而解析可以在初始化之前也可在初始化之后,为了支持java语言的动态绑定(或者叫运行时绑定)。


加载


通过类的全名获取二进制字节流,字节流存入方法区,堆中生成一个Class对象,作为方法区数据结构访问的入口


验证


文件格式验证:是否满足Class文件规范


元数据验证


字节码验证


符号引用验证


准备


类的静态变量会在类准备阶段分配内存


赋予初始值(0,null,false等),而java中显式赋值的操作是在类初始化的时候执行。

类的初始化


类只有在主动使用时,虚拟机才会对类进行初始化,被动使用不会初始化。


主动引用的情况:


  • New实例化
  • 访问静态变量、静态方法
  • 反射访问


初始化类时,如有父类,父类也会被初始化


Main方法所在类会先被初始化.


调用父类静态变量,子类被称为被动引用,不会初始化。


被动引用的情况:


  • 引用静态变量,定义该常量的类不会初始化
  • 数组定义类


实例1:

public class Parent{
    public static int parent = 0;
    static{
        System.out.println("Parent init...");
    }
}
public class Child extends Parent{
    public static int child=Parent.parent;
    static{
        System.out.println("Child init...");
    }
public Child(){
        System.out.println("Child init by constructor...");
    }
}
public class ClassLoaderTest{
    public static void main(String[]args){
        System.out.println(Child.parent);
    }
}


输出结果:

Parent init...
0


分析


1:子类调用父类的静态变量,父类会被初始化,子类不会被初始化,也就是说对于静态变量,只有直接定义该变量的类才会被初始化。所以Child.parent时,Child不会初始化,Parent初始化。


2:类的static方法在类初始化的时候会被执行(注意:是初始化时执行,而并非类加载时执行)。所以Child类的static和构造方法都不会被执行。而parent的static方法会被执行。


实例2:

public class Child{
    public static Child child = Child.getInstance();
    public static int num = 2;
    public static Child getInstance(){
        num++;
        System.out.println("instance:num=" + num);
        returnchild;
    }
    public Child(){
        System.out.println("Child init...");
        num++;
        System.out.println("Constructor:num="+num);
    }
}
public class ClassLoaderTest{
    public static void main(String[]args){
        System.out.println("main:num="+Child.num);
    }
}


输出结果:

instance:num=1
main:num=2


这个就有点意思了,为什么instance:num不为2或3,而为1了?。


分析


1:类的静态变量会在类准备阶段分配内存,并赋予初始值(0,null等),而java中显式赋值的操作是在类初始化的时候执行。


2:访问child.num时会触发Child的初始化,但是第一行代码child=Child.getinstance()执行时,类尚未完成初始化,所以此时num在内存中的值为0,执行++后为num=1,而当类完成初始化时,num的值又被重置为2,所以main:num=2;


3:如果将Childchild = Child.getInstance();int num = 2;换下位置,可以得到num值都为3,可自行测试。


类加载器


类加载的双亲委派机制是当类加载器收到一个类加载请求是,首先不会自己尝试加载,而是交由父加载器加载,父加载器同样会委派上级加载器加载,最终会交由启动类加载器加载,而上级加载器在指定目录下没有找到指定类时再交给下级加载器加载(如果最下级加载也没有找到类会抛出ClassNotFound异常),这种机制的好处就是一个类不管由哪个加载器加载,最终得到的是相同的对象。


image.png

双亲委派


相关文章
|
4月前
|
Arthas 存储 算法
深入理解JVM,包含字节码文件,内存结构,垃圾回收,类的声明周期,类加载器
JVM全称是Java Virtual Machine-Java虚拟机JVM作用:本质上是一个运行在计算机上的程序,职责是运行Java字节码文件,编译为机器码交由计算机运行类的生命周期概述:类的生命周期描述了一个类加载,使用,卸载的整个过类的生命周期阶段:类的声明周期主要分为五个阶段:加载->连接->初始化->使用->卸载,其中连接中分为三个小阶段验证->准备->解析类加载器的定义:JVM提供类加载器给Java程序去获取类和接口字节码数据类加载器的作用:类加载器接受字节码文件。
403 55
|
2月前
|
存储 Java 编译器
深入理解Java虚拟机--类文件结构
本内容介绍了Java虚拟机与Class文件的关系及其内部结构。Class文件是一种与语言无关的二进制格式,包含JVM指令集、符号表等信息。无论使用何种语言,只要能生成符合规范的Class文件,即可在JVM上运行。文章详细解析了Class文件的组成,包括魔数、版本号、常量池、访问标志、类索引、字段表、方法表和属性表等,并说明其在Java编译与运行过程中的作用。
|
5月前
|
Arthas 监控 Java
Arthas redefine(加载外部的.class文件,redefine到JVM里 )
Arthas redefine(加载外部的.class文件,redefine到JVM里 )
179 15
|
5月前
|
Arthas 监控 Java
Arthas sc(查看JVM已加载的类信息 )
Arthas sc(查看JVM已加载的类信息 )
181 9
|
7月前
|
存储 算法 Java
JVM: 内存、类与垃圾
分代收集算法将内存分为新生代和老年代,分别使用不同的垃圾回收算法。新生代对象使用复制算法,老年代对象使用标记-清除或标记-整理算法。
89 6
|
6月前
|
Java
jvm类常见加载顺序
jvm类常见加载顺序
|
12月前
|
安全 Java 应用服务中间件
JVM常见面试题(三):类加载器,双亲委派模型,类装载的执行过程
什么是类加载器,类加载器有哪些;什么是双亲委派模型,JVM为什么采用双亲委派机制,打破双亲委派机制;类装载的执行过程
274 35
JVM常见面试题(三):类加载器,双亲委派模型,类装载的执行过程
|
9月前
|
存储 安全 Java
JVM加载过程
JVM类加载过程是Java开发中的关键环节,主要包括五个阶段:加载、验证、准备、解析和初始化。加载阶段获取类的二进制字节流;验证确保字节码符合规范;准备为静态变量分配内存并默认初始化;解析将符号引用转为直接引用;初始化执行静态变量赋值和静态代码块。了解这一过程有助于深入理解Java程序运行机制,提升编程水平。
|
11月前
|
缓存 前端开发 Java
JVM知识体系学习二:ClassLoader 类加载器、类加载器层次、类过载过程之双亲委派机制、类加载范围、自定义类加载器、编译器、懒加载模式、打破双亲委派机制
这篇文章详细介绍了JVM中ClassLoader的工作原理,包括类加载器的层次结构、双亲委派机制、类加载过程、自定义类加载器的实现,以及如何打破双亲委派机制来实现热部署等功能。
482 3
|
11月前
|
小程序 Oracle Java
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
这篇文章是关于JVM基础知识的介绍,包括JVM的跨平台和跨语言特性、Class文件格式的详细解析,以及如何使用javap和jclasslib工具来分析Class文件。
204 0
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用