Java中和对象有关的的内存图

一.Java的内存划分

Java的内存就像一间房子的划分一样,分为厨房,客厅,卧室。每个划分区域各司其职。Java的内存被划分为五个部分。
1.栈(Stack)

  • 存放的都是方法中的局部变量。
  • 方法的运行一定是在栈中的。
  • 局部变量:方法的参数,或者是方法{}内部的变量。
  • 局部变量的特点:有作用域,一旦超出作用域,就立刻从栈中消失。

2.堆(Heap)

  • 凡是new出来的东西,都存在于堆中。
  • 堆内存中的东西都有一个16进制的地址值。
  • 堆内存里存放的数据都有默认的值;
    —整数的默认值为0
    —浮点数的默认值为0.0
    —字符的默认值“\u0000”
    —布尔的默认值false
    —引用类型默认值为null

3.方法区(Method Area)

  • 存储 .class 相关的方法,包含方法的信息。
  • 有一个静态区存放静态数据

4.方法区(Native Method Stack)

  • 与操作系统相关的信息

5.寄存器(pc Register)

  • 与cpu相关的信息

二.对象有关内存图

只有一个对象的内存图

在这里插入图片描述
1 从方法区开始,存储 .class 相关的成员变量,和成员方法,如图中的 Phone.class,Demo01PhoneOne.class 中的变量。
2 main方法进栈,在栈中为 main方法开辟一个区域。
3进入 main方法中.
4 mian方法中第一句 Phone one = new Phone();
在main的区域中创建一个局部变量 Phone one,此变量保存的是堆中new Phone()的地址值。在堆中创建一个Phone对象,给其成员变量附上初始值,成员方法保存的是方法区中对应成员方法的地址值(0x333)如绿线。最后new Phone()也有一个地址值,我们把它赋值给Phone one 如红线。
5 赋值;one.brand = “苹果”,one.price = “8388.0”, one.color = “黑色”。就是通过 phone one 保存的地址找到堆中的 phone 对象,再找到他的属性,修改其中的值。也图中红色线条的路径。
6 方法执行 ; one.call(“乔布斯”),one.sendMessage()两个方法。
7 先执行one.call(“乔布斯”),先通过红线找到堆中的 new Phone(),在堆中对象 new Phone 中找到成员方法所保存的地址值,通过此地址值在方法区中找到对应的方法存储区域(也就是绿色框框),在此区域中找到 call(String who)方法,也就是图中绿色线条的路径。。 call(String who)方法想要运行必须入栈,call方法入栈之后,也给他划分一个区域,然后执行方法:“给谁打电话”。参数 who是乔布斯,传递给了栈中将要运行的方法,如图中蓝线所示路径。
8 call方法运行完成,就要出栈,在这里我们用一个差号表示出栈。
9 one.sendMessage() 方法的运行过程同call(String who)方法。
10 main中所有的语句都运行完成了, main方法也要出栈。

两个对象使用同一个方法的内存图

这里没什么好说的,new出来的对象是不同的,但堆中两个new出来的对象成员方法所存的地址都是相同的,都是方法区中的同一个,如绿色线所示。
在这里插入图片描述

两个引用指向同一个对象的内存图

代码变化的地方已经用红圈标识出来了。就是把one中保存对象的地址赋值给two。即one个two共用一个堆中的new Phone对象,如红线所示。如果 “只有一个对象的内存图” 懂了的话,这个应该也不难。
在这里插入图片描述

使用对象类型作为方法参数的内存图

在这里插入图片描述
method(one)方法执行前的内存图流程我就不在赘述了,直接从method(one)开始。首先在方法区中找到method方法 ,然后压入栈中。进栈之后要开辟一个内存给它使用。这个内存空间是怎么来的?就是根据method(one)调用而来的,如蓝线所示。
one怎么作为参数传入到method方法中的呢?
首先Phone one存储存储的是一个地址值(0x666)。
method(one)中的one也就是地址值(0x666)。如【1】线路。
然后param 接收one存储的地址值(0x666)。如【2】线路
param.brand,也就是0x666.brand。如【3】线路。
通过0x666能找到堆中的对象,也就能找到对象中的brand成员变量。
总结:当一个对象作为参数,传递到方法当中去时,实际上传递进去的是对象的地址值。

使用对象类型作为方法返回值的内存图

在这里插入图片描述
完整的流程:
1 方法区存 .class 的相关信息(成员变量,成员方法),代码中有两个 .class 文件。
2 main方法入栈,开辟内存空间。
3 Phone two = getPhone();调用了getPhone();方法,看方法区中有没有,有的话,通过蓝线调用入栈。开辟内存空间
4 Phone one = new Phone();
在getPhone的工作空间中,创建一个成员变量Phone one。在堆中创建一个new Phone();给其中的成员变量赋初始值。给成员变量赋上 方法区 中成员方法的地址值,如绿线。new Phone()也有一个地址值,在栈中我们用 Phone one 保存。
5 修改one中成员变量的值,这个操作不用多说了,通过地址值找到堆中对象,再去找此对象的成员变量,修改即可。
6 return one ; 也就是返回one 中所存的地址值。
7 main的内存空间中,成员变量Phone two接收到 返回的地址值。two.brand也就变成了0x666.brand。即可访问到堆中对象的成员方法。

总结:当使用一个对象类型作为方法的返回值时,返回值其实就是对象的地址值。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值