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、构造函数执行完成,对象创建结束。

目录
相关文章
|
5天前
|
存储 Java 对象存储
JVM(内存区域划分)
JVM(内存区域划分)
14 1
|
7天前
|
存储 安全 Java
synchronized原理-字节码分析、对象内存结构、锁升级过程、Monitor
本文分析的问题: 1. synchronized 字节码文件分析之 monitorenter、monitorexit 指令 2. 为什么任何一个Java对象都可以成为一把锁? 3. 对象的内存结构 4. 锁升级过程 (无锁、偏向锁、轻量级锁、重量级锁) 5. Monitor 是什么、源码查看(hotspot虚拟机源码) 6. JOL工具使用
|
14天前
|
前端开发 安全 Java
深入浅出JVM(八)之类加载器
深入浅出JVM(八)之类加载器
|
14天前
|
存储 缓存 算法
深入浅出JVM(二)之运行时数据区和内存溢出异常
深入浅出JVM(二)之运行时数据区和内存溢出异常
|
2天前
|
存储 Java 开发者
深入理解Java虚拟机:JVM内存模型解析
【5月更文挑战第27天】 在Java程序的运行过程中,JVM(Java Virtual Machine)扮演着至关重要的角色。作为Java语言的核心执行环境,JVM不仅负责代码的执行,还管理着程序运行时的内存分配与回收。本文将深入探讨JVM的内存模型,包括其结构、各部分的作用以及它们之间的相互关系。通过对JVM内存模型的剖析,我们能够更好地理解Java程序的性能特征,并针对性地进行调优,从而提升应用的执行效率和稳定性。
|
2天前
|
Java
<Java SE> 5道递归计算,创建数组,数组遍历,JVM内存分配...
<Java SE> 5道递归计算,创建数组,数组遍历,JVM内存分配
22 2
|
2天前
|
存储 Java 程序员
【JVM】类的声明周期(加载、连接、初始化)
【JVM】类的声明周期(加载、连接、初始化)
8 1
|
14天前
|
存储 安全 Java
Python中的引用和赋值机制允许变量引用内存中的对象,并通过引用计数来管理对象的生命周期
【5月更文挑战第14天】Python中的变量是对象引用,不存储数据,而是在内存中创建对象。赋值操作创建新变量并使其指向已有对象。引用计数用于管理对象生命周期,引用数为0时对象被回收。理解这些机制对编写高效Python代码很重要。
32 6
|
14天前
|
Java Linux Arthas
linux上如何排查JVM内存过高?
linux上如何排查JVM内存过高?
830 0
|
14天前
|
存储 缓存 算法
深入浅出JVM(十四)之内存溢出、泄漏与引用
深入浅出JVM(十四)之内存溢出、泄漏与引用