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

双亲委派


相关文章
|
1月前
|
安全 Java 应用服务中间件
JVM常见面试题(三):类加载器,双亲委派模型,类装载的执行过程
什么是类加载器,类加载器有哪些;什么是双亲委派模型,JVM为什么采用双亲委派机制,打破双亲委派机制;类装载的执行过程
JVM常见面试题(三):类加载器,双亲委派模型,类装载的执行过程
|
8天前
|
缓存 前端开发 Java
JVM知识体系学习二:ClassLoader 类加载器、类加载器层次、类过载过程之双亲委派机制、类加载范围、自定义类加载器、编译器、懒加载模式、打破双亲委派机制
这篇文章详细介绍了JVM中ClassLoader的工作原理,包括类加载器的层次结构、双亲委派机制、类加载过程、自定义类加载器的实现,以及如何打破双亲委派机制来实现热部署等功能。
19 3
|
8天前
|
小程序 Oracle Java
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
这篇文章是关于JVM基础知识的介绍,包括JVM的跨平台和跨语言特性、Class文件格式的详细解析,以及如何使用javap和jclasslib工具来分析Class文件。
21 0
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
|
5月前
|
前端开发 安全 Java
深入浅出JVM(八)之类加载器
深入浅出JVM(八)之类加载器
|
3月前
|
Java Perl
JVM内存问题之如何统计在JVM的类加载中,每一个类的实例数量,并按照数量降序排列
JVM内存问题之如何统计在JVM的类加载中,每一个类的实例数量,并按照数量降序排列
|
3月前
|
存储 安全 Java
开发与运维引用问题之JVM类加载过程如何解决
开发与运维引用问题之JVM类加载过程如何解决
24 0
|
4月前
|
Java 编译器
Java健壮性 Java可移植性 JDK, JRE, JVM三者关系 Java的加载与执行原理 javac编译与JAVA_HOME环境变量介绍 Java中的注释与缩进 main方法的args参数
Java健壮性 Java可移植性 JDK, JRE, JVM三者关系 Java的加载与执行原理 javac编译与JAVA_HOME环境变量介绍 Java中的注释与缩进 main方法的args参数
46 1
|
3月前
|
存储 算法 Java
JAVA程序运行问题之Java类加载到JVM中加载类时,实际上加载的是什么如何解决
JAVA程序运行问题之Java类加载到JVM中加载类时,实际上加载的是什么如何解决
|
5月前
|
监控 Java 测试技术
滚雪球学Java(45):探秘Java Runtime类:深入了解JVM运行时环境
【5月更文挑战第20天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
41 1
滚雪球学Java(45):探秘Java Runtime类:深入了解JVM运行时环境
|
4月前
|
安全 前端开发 Java
《JVM由浅入深学习【一】 》JVM由简入深学习提升(类加载过程+父子类加载过程+类加载器+双亲委派机制)
《JVM由浅入深学习【一】 》JVM由简入深学习提升(类加载过程+父子类加载过程+类加载器+双亲委派机制)
37 0