JVM加载对象时内存加载顺序

简介: 在开发中,有时会遇到这样的情况:我明明给一个变量赋值了,为什么在使用该变量时却是没有值的,这个和JVM的内存加载顺序有关,当你使用该变量时,这个变量还没初始化完成。 首先我们来看一段代码:public class ObjectLoadMemoryTest extend...

在开发中,有时会遇到这样的情况:我明明给一个变量赋值了,为什么在使用该变量时却是没有值的,这个和JVM的内存加载顺序有关,当你使用该变量时,这个变量还没初始化完成。
首先我们来看一段代码:

public class ObjectLoadMemoryTest extends FuTest{

    private int INT =100;
    private final int FINAL_INT =100;
    private final Integer FINAL_INTEGER = 100;
    private static Integer STATIC_INTEGER = 100;
    private String STR1 = "abc";
    private final String FINAL_STR1="abc";
    private final String FINAL_STR2 = new String("abc");
    private final List<String> FINAL_LIST = new ArrayList<String>();

    public ObjectLoadMemoryTest() {
        System.out.println("ObjectLoadMemoryTest开始执行构造。。。。。。");
        doDisplay();
    }

    @Override
    public void doDisplay() {
        System.out.println(INT);
        System.out.println(FINAL_INT);
        System.out.println(FINAL_INTEGER);
        System.out.println(STATIC_INTEGER);
        System.out.println(STR1);
        System.out.println(FINAL_STR1);
        System.out.println(FINAL_STR2);
        System.out.println(FINAL_LIST);
    }

    public static void main(String[] args) {
        new ObjectLoadMemoryTest();
    }


}

abstract class FuTest{

    public FuTest(){
        System.out.println("FuTest构造开始执行。。。。。");
        doDisplay();
    }

    public abstract void doDisplay();
}

这段代码的逻辑很简单,就是在初始化子类对象的时候,调用这个类中的方法doDisplay,这个方法会打印该类中的所有的属性,我们可以通过观察打印结果来分析一下jvm在创建对象的时候,内存是如何加载的。
运行结果如下:

FuTest构造开始执行。。。。。
0
100
null
100
null
abc
null
null
ObjectLoadMemoryTest开始执行构造。。。。。。
100
100
100
100
abc
abc
abc
[]

我们发现在调用子类的构造函数的时候,会先调用父类的构造,在父类中我们同样会打印所有的属性,发现和子类中打印的结果是不一样的。
通过打印结果,我们可以分析到以下几点:

  • 基本数据类型的默认初始化是在构造函数之前,但是其显示初始化却是在调用父类构造函数之后执行的
  • 使用final修饰的基本数据类型及String类型,在调用父类构造函数之前就已经显示初始化完成了
  • 即使使用了final修饰,属性如果是一个对象,那么它也会在调用父类构造函数之后执行
  • 使用static修饰的属性,都是在调用父类构造之前就显示初始化了

由此,我们可以推断出如下结果:
类的加载过程:
1、启动JVM,加载程序中需要使用的class文件。
2、在加载class文件的时候,所有的静态内容(静态成员变量,静态成员函数,静态代码块)都要加载到方法区的静态区中。
3、当类中的所有静态加载完成之后,开始给类中的所有静态成员变量默认初始化。
4、类中的所有静态成员变量默认初始化完成之后,开始给这些静态成员变量显示赋值。
5、所有静态成员变量显示赋值结束之后,开始运行类中的静态代码块。
6、当所有的静态代码块执行完成,代表当前这个class文件才彻底被加载结束。

对象的创建过程:
1、使用new关键字创建对象,在堆给对象分配内存空间。
2、给对象所属类中的所有非静态成员变量分配空间并进行默认的初始化。
3、执行和new对象时传递参数一致的构造函数。
4、执行构造函数的的过程中有隐式的三步:
4.1、执行super() 语句,找父类的空参数构造函数
4.2、给非静态成员变量进行显示赋值。
4.3、运行构造代码块
4.4、构造函数中的自己写的代码执行。
5、构造函数执行完成,对象创建结束。

目录
相关文章
|
12天前
|
Java Docker 索引
记录一次索引未建立、继而引发一系列的问题、包含索引创建失败、虚拟机中JVM虚拟机内存满的情况
这篇文章记录了作者在分布式微服务项目中遇到的一系列问题,起因是商品服务检索接口测试失败,原因是Elasticsearch索引未找到。文章详细描述了解决过程中遇到的几个关键问题:分词器的安装、Elasticsearch内存溢出的处理,以及最终成功创建`gulimall_product`索引的步骤。作者还分享了使用Postman测试接口的经历,并强调了问题解决过程中遇到的挑战和所花费的时间。
|
11天前
|
存储 算法 Oracle
不好意思!耽误你的十分钟,JVM内存布局还给你
先赞后看,南哥助你Java进阶一大半在2006年加州旧金山的JavaOne大会上,一个由顶级Java开发者组成的周年性研讨会,公司突然宣布将开放Java的源代码。于是,下一年顶级项目OpenJDK诞生。Java生态发展被打开了新的大门,Java 7的G1垃圾回收器、Java 8的Lambda表达式和流API…大家好,我是南哥。一个Java学习与进阶的领路人,相信对你通关面试、拿下Offer进入心心念念的公司有所帮助。
不好意思!耽误你的十分钟,JVM内存布局还给你
|
19天前
|
存储 算法 Java
JVM自动内存管理之垃圾收集算法
文章概述了JVM内存管理和垃圾收集的基本概念,提供一个关于JVM内存管理和垃圾收集的基础理解框架。
JVM自动内存管理之垃圾收集算法
|
19天前
|
存储 Java 程序员
JVM自动内存管理之运行时内存区
这篇文章详细解释了JVM运行时数据区的各个组成部分及其作用,有助于理解Java程序运行时的内存布局和管理机制。
JVM自动内存管理之运行时内存区
|
23天前
|
存储 Java 程序员
Java中对象几种类型的内存分配(JVM对象储存机制)
Java中对象几种类型的内存分配(JVM对象储存机制)
53 5
Java中对象几种类型的内存分配(JVM对象储存机制)
|
30天前
|
存储 安全 Java
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程,JDK、JRE、JVM关系;程序计数器,堆,虚拟机栈,堆栈的区别是什么,方法区,直接内存
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程是什么,JDK、JRE、JVM的联系与区别;什么是程序计数器,堆,虚拟机栈,栈内存溢出,堆栈的区别是什么,方法区,直接内存
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程,JDK、JRE、JVM关系;程序计数器,堆,虚拟机栈,堆栈的区别是什么,方法区,直接内存
|
17天前
|
存储 安全 Java
JVM内存结构
这篇文章详细介绍了Java虚拟机(JVM)的内存结构,包括类的加载过程、类加载器的双亲委派机制、沙箱安全机制、程序计数器、Java栈、Java堆、本地方法和本地方法栈等关键组件及其作用。
JVM内存结构
|
16天前
|
搜索推荐 Java API
Electron V8排查问题之分析 node-memwatch 提供的堆内存差异信息来定位内存泄漏对象如何解决
Electron V8排查问题之分析 node-memwatch 提供的堆内存差异信息来定位内存泄漏对象如何解决
15 0
|
18天前
|
算法 Java
JVM自动内存管理之垃圾收集器
这篇文章是关于Java虚拟机(JVM)自动内存管理中的垃圾收集器的详细介绍。
|
2月前
|
运维 Java Linux
(九)JVM成神路之性能调优、GC调试、各内存区、Linux参数大全及实用小技巧
本章节主要用于补齐之前GC篇章以及JVM运行时数据区的一些JVM参数,更多的作用也可以看作是JVM的参数列表大全。对于开发者而言,能够控制JVM的部分也就只有启动参数了,同时,对于JVM的性能调优而言,JVM的参数也是基础。

热门文章

最新文章

下一篇
云函数