Java中各种数据的在虚拟机内存中的存储方式(超具象!!)
一、前提须知
1.前提:
数据类型,分为
基本数据类型(数值型,字符型,布尔型)
引用类型(类,接口,数组,[当然引用类型也有根据引用级别来进行分类的]);
可以到以下链接对各种数据类型进行了解:
[link](https://wenku.baidu.com/view/c2172a33dd3383c4ba4cd216.html)
2.任何数据类型在声明时都会在栈中开辟内存空间;
3.虚拟机内存分为栈、方法区、堆三个部分;
4.一般讨论内存,都是默认讨论方法区和堆中的内存,而不讨论栈中内存(可能是声明时一定会开辟空间,所以默认不算)
二、根据数据类型的不同,讨论各种数据在内存中的存储方式
1.基本数据类型
*声明时,只在栈中开辟空间,初始化(即赋值时),值也是放在栈中;
![](https://i-blog.csdnimg.cn/blog_migrate/40d3104472606b4b204c4219154caef6.jpeg)
int a = 123; //创建一个整型类型的变量a
此时,在栈中会开辟一个叫a的房间,里面就住着123;
![](https://i-blog.csdnimg.cn/blog_migrate/81701136ffc9b3d9298f6f480df257af.jpeg)
2.引用类型(String类型较特殊)
声明时,在栈中开辟空间,初始化(即赋值时),会在方法区和堆开辟内存空间,方法区内存空间中放的是引用类型变量的值,堆中空间放的则是对应值在方法区中的地址(堆中存放的都是地址);
int b[] = {1,2,3}; //创建一个一维数组b
此时,会在栈中开一个叫b的房间,房间里放着一把钥匙(b在堆中的地址001),而在堆中也会开辟一个房间(假设是001号房间),001房间放着3把钥匙(b的值1、2、3的3个地址A,B,C),在方法区中会开辟三个房间A,B,C,里面分别放着1,2,3
PS:创建b的时候总共开辟了四个内存空间(在堆中的1个房间,在方法区中的三个房间);
![](https://i-blog.csdnimg.cn/blog_migrate/08f246c6d7d8e02dea403ba4b9351257.jpeg)
3.特殊的String类型
String类型数据,同样会在方法区和堆开辟内存空间,但是在方法区中有个字符串常量池(String类型专用) ,用来存放String类型对象的值
![](https://i-blog.csdnimg.cn/blog_migrate/e63a2c43d188836637143ac0258f4e8a.jpeg)
String c = "死鱼不要太安乐"; //创建string类型变量c
String d = new String("死鱼有点南"); //创建一个String类型的对象d
String e = new String("死鱼有点南")
此部分为jdk1.7版本前的逻辑,下方更新说明了1.7后的内存使用情况
此时,在栈中和堆中开辟房间的方式和其他引用类型数据一样,而在方法区中的字符串常量池,其中只开辟了两个房间D,E,放着"死鱼不要太安乐"以及"死鱼有点南",因为字符串常量池中若值相同则只会开辟一个内存空间。
PS:创建d,e对象的时候总共开辟了三个内存空间(2个堆中的房间,1个方法区中字符串常量池中的房间);
此时的若输出 d==e 的布尔值(下图b代表d,c代表e),结果为:
原因: “==” 比较运算符只会比较变量的地址,而b,c在堆中的房间号(即地址一个为002,一个为003)是不同的,所以结果为false
更新!!对上述第三部分进行修订
如上图为修改部分,在JDK1.7后,方法区中的常量池,记录的是对象在堆中的引用。
因此d对象创建时,堆中先开辟002空间,其会先到方法区的常量池中,查看是否有"死鱼有点南",这个值的引用,如果没有,则创建了B,并且堆中开辟了空间005,B指向005,结束对象的创建
当e对象创建时,堆中先开辟003空间,此时方法区的常量池中,已经有"死鱼有点南",这个值的引用,为005,因此,不需要再在方法区中创建C空间了,003同样指向B即可(PS:如果没有该值,则会开辟C空间,堆中也会开辟006被C所指向)
以上皆为个人理解及看法,内容还待补充,若有误还望请教以便及时更正