java 创建对象的内存图解 (通俗易懂)

简介: Java 内存图解篇之创建对象的内存图解,非常详细,适合初学者!

目录

前言 :

一、代码准备 :

二、内存图解 :

       ①加载含main类的字节码文件

       ②main进栈

       ③执行main中代码        

       ④new关键字开始

       ⑤在堆中开辟空间

       ⑥默认初始化

       ⑦显式初始化

       ⑧构造器初始化

        ⑨常量池

       ⑩new关键字结束        

       ⑩①成员方法的使用细节1

       ⑩②成员方法使用细节2

三、小结 :


前言 :

       我们知道,Java内存分配的三大主要空间分别是 : ①栈空间,②堆空间,③方法区。但是,当我们实例化一个对象时,三大空间到底是如何配合的呢?今天就为大家带来Java创建对象的内存图解,尽力给大家讲得通俗、透彻一点。走起!

一、代码准备 :

       我们以Phone类为准备实例化的类,以TestPhone类为测试类

       Phone类代码如下 :

packageknowledge.constructor.memory;
publicclassPhone {
//成员变量privateintyear=1;               //手机使用年限privateStringbrand="Xiaomi";    //手机品牌 //空参构造publicPhone() {
    }
//带参构造publicPhone(intyear, Stringbrand) {
this.year=year;
this.brand=brand;
    }
//setter,getter方法publicintgetYear() {
returnyear;
    }
publicvoidsetYear(intyear) {
this.year=year;
    }
publicStringgetBrand() {
returnbrand;
    }
publicvoidsetBrand(Stringbrand) {
this.brand=brand;
    }
}

image.gif

       TestPhone类代码如下 :

packageknowledge.constructor.memory;
publicclassTestPhone {
publicstaticvoidmain(String[] args) {
PhonepDemo=newPhone(2,"Huawei");
System.out.println("品牌是:"+pDemo.getBrand());
System.out.println("年限为:"+pDemo.getYear());
    }
}

image.gif

       输出结果image.png

二、内存图解 :

       (u‿ฺu)好滴,我们就以上面的代码为栗,给大家分析一下,在实例化Phone类对象时,内存中究竟发生了神马:

       ①加载含main类的字节码文件

               因为main() 函数是程序的唯一入口,因此,包含main函数的Phone类的字节码文件优先加载到方法区。如下图所示 :

image.png

       ②main进栈

               main函数进栈 ,如下图所示 :

image.png

       ③执行main中代码        

               开始执行main方法的第一行代码,从右向左执行,首先便遇到了new关键字,因为new关键字后面出现了Phone类,表示要实例化的是Phone类,而Phone类的字节码文件还没有加载到方法区,jvm不认识Phone,因此下一步是将Phone类的字节码文件加载到方法区(假设Phone类成员方法在方法区中的地址值为0x0088),如下图所示 :

image.png

               注意,这张图右下角Phone类的字节码文件那里,应该是private String brand,不小心写错了😂,但是不影响理解,下张图就改过来了🙏

       ④new关键字开始

               Phone类的字节码文件加载到方法区之后,new关键字会在堆内存开辟空间给新的Phone类对象,假设Phone类对象在内存中的地址值为0x0011。如下图所示 :          

image.png

       ⑤在堆中开辟空间

               根据Phone类的字节码文件,在堆中分配的这块内存空间会被分成三部分分别是属性值year,brand,和Phone类的成员方法,Phone类的成员方法部分其实是成员方法在方法区中的地址值,将来如果对象调用成员方法,可以通过这个地址值找到方法区中的成员方法。如下图所示 :

image.png

       ⑥默认初始化

                对对象的属性值进行第一次初始化 : 默认初始化。对应于Phone类中,year是int类型默认值0;brand是String类型默认值null,如下图 :

image.png

       ⑦显式初始化

               因为我们在定义Phone类时,对year和brand分别赋了初值,因此默认初始化之后,要进行第二次初始化 : 显式初始化。(如果类中没有对属性赋初值,没有这一步骤),如下图所示:

image.png 

       ⑧构造器初始化

                创建一个对象,需要构造器来进行构造器初始化,因为我们调用的是Phone类的带参构造,因此要进行第三次初始化 : 构造器初始化。即将属性值更改为调用带参构造时传入的形参

image.png    

        ⑨常量池

                这里的字符串常量"Huawei",在常量池中,也有自己的地址,调用模式类似于成员方法。brand属性这里其实保存的是"Huawei"在常量池中的地址值,如下图所示 :

image.png    

       ⑩new关键字结束        

                最后,把对象的地址值返回给pDemo引用就可以了,如下图所示 :

image.png

               到这里new关键字的任务就算是完成了,当我们通过"对象." 的形式来调用时,实质就是通过引用pDemo指向的堆内存中对象的地址,进一步找到对象的成员变量或者成员方法

       ⑩①成员方法的使用细节1

               继续执行main方法中的代码,下一行是一条输出语句,但是输出内容中调用了pDemo对象的成员方法,因此,JVM会先通过pDemo这个引用找到堆内存中的对象,然后,再通过对象中成员方法的地址,找到方法区中的成员方法,进行调用。如下图所示 :

image.png

       ⑩②成员方法使用细节2

               调用成员方法时,成员方法也要进栈,如下图所示 :

image.png                        

               下一行调用getYear成员方法也是同理,不再赘述。大家一定要记住,我们说的对象,其本质指的就是堆内存中的这一块区域,创建对象的那个变量,只是对该区域的一个引用,相当于一个指针指向了这里。 但平时工作学习中,我们将其简称为了什么什么对象,但它的本质一定要清楚。

              Δ注意 :

       栈中调用成员方法时,会根据创建的对象的地址,找到堆中成员方法的地址,继而找到方法区中的成员方法,接着,成员方法进栈。  

       栈中调用字符串常量等常量时,会根据创建的对象的地址,找到堆中成员变量的地址,继而找到方法区里面常量池中常量的地址。                    

三、小结 :

       以上就是Java中创建对象的内存图解,我自认为讲得已经够详细了😂,如果发现有问题,欢迎指正,大家一起交流。感谢阅读。

System.out.println("END---------------------------------------------------------------------------");

目录
相关文章
|
15天前
|
存储 SQL 缓存
揭秘Java并发核心:深度剖析Java内存模型(JMM)与Volatile关键字的魔法底层,让你的多线程应用无懈可击
【8月更文挑战第4天】Java内存模型(JMM)是Java并发的核心,定义了多线程环境中变量的访问规则,确保原子性、可见性和有序性。JMM区分了主内存与工作内存,以提高性能但可能引入可见性问题。Volatile关键字确保变量的可见性和有序性,其作用于读写操作中插入内存屏障,避免缓存一致性问题。例如,在DCL单例模式中使用Volatile确保实例化过程的可见性。Volatile依赖内存屏障和缓存一致性协议,但不保证原子性,需与其他同步机制配合使用以构建安全的并发程序。
47 0
|
15天前
|
安全 Java 开发者
Java 内存模型解析与实践
在Java的世界中,理解内存模型对于编写高效、线程安全的代码至关重要。本文将深入探讨Java内存模型的核心概念,并通过实例分析其对并发编程的影响,旨在为读者提供一套实用的策略和思考方式来优化多线程应用的性能与安全性。
33 0
|
15天前
|
存储 监控 算法
Java内存管理:从垃圾收集到性能优化
【8月更文挑战第4天】在Java的世界中,内存管理是一块神秘的领域,它不仅关乎程序的稳定运行,更直接影响到系统的性能表现。本文将带你深入理解Java的垃圾收集机制,探讨如何通过合理的内存管理策略来提升应用效率。我们将一起分析JVM内存结构,探索不同的垃圾收集算法,并借助实际代码示例,学习如何监控和调优内存使用,以期达到减少延迟、防止内存泄漏的目的。
|
11天前
|
存储 Java 程序员
Java中对象几种类型的内存分配(JVM对象储存机制)
Java中对象几种类型的内存分配(JVM对象储存机制)
45 5
Java中对象几种类型的内存分配(JVM对象储存机制)
|
4天前
|
存储 Java 开发者
Java 内存模型与垃圾回收机制的深度剖析
在Java的世界里,理解其内存模型和垃圾回收机制是提升编程效率的关键。本文将通过浅显易懂的语言,带你深入了解Java的内存分配原理和垃圾回收过程,让你对Java的性能调优有更深刻的认识。
|
7天前
|
安全 Java 程序员
深入浅出Java内存模型:探索JMM的奥秘
在Java编程世界中,理解其内存模型(JMM)是提升代码性能和确保线程安全的关键。本文将带你走进Java内存模型的大门,通过浅显易懂的方式揭示其工作原理,并指导你如何在实际开发中有效利用JMM来避免常见的并发问题。
|
13天前
|
算法 Java 开发者
Java 内存管理:深入理解垃圾收集机制
在Java的世界中,内存管理是一块基石,它确保了程序的顺畅运行和资源的合理利用。本文将带你深入探讨Java的垃圾收集机制,揭示其工作原理、常见算法以及调优实践。我们将一起探索如何通过理解这一机制来编写更高效的代码,避免内存泄漏,并提升应用性能。
|
9天前
|
Java 开发者
深入浅出Java内存管理
在Java的世界里,内存管理是支撑程序运行的基石。本文将通过浅显易懂的语言和生动的比喻,带你了解Java是如何巧妙地处理内存分配与回收的。我们将一起探索对象在Java内存模型中的生命周期,以及JVM如何通过垃圾收集机制保持内存的健康状态。无论你是初学者还是有一定经验的开发者,这篇文章都将为你揭开Java内存管理的神秘面纱。
|
14天前
|
监控 算法 Java
Java 内存管理:从垃圾收集到性能调优
【8月更文挑战第5天】 本文将深入探讨 Java 的内存管理机制,特别是垃圾收集器(GC)的工作原理及其在性能优化中的关键作用。通过具体案例分析,我们将了解如何选择合适的垃圾收集算法以及调优 JVM 参数来提升应用性能。文章旨在为 Java 开发者提供实用的内存管理和性能调优技巧,帮助他们编写更高效、更稳定的应用程序。
36 3
|
16天前
|
存储 Java 编译器
Java内存区域与内存溢出异常 - 运行时数据区
【8月更文挑战第2天】Java运行时数据区包括:1) 程序计数器:记录线程执行字节码的行号,线程私有;2) Java虚拟机栈:描述方法执行的内存模型,线程私有,深度过大抛出`StackOverflowError`;3) 本地方法栈:服务于Native方法,线程私有;4) Java堆:所有线程共享,对象实例在此分配内存;5) 方法区:存储类信息、常量等数据;6) 运行时常量池:方法区的一部分,存放字面量和符号引用。不当使用如无限创建对象或过度递归调用会导致各种内存溢出错误。