(1)栈内存空间:保存所有的对象名称(更准确地说是保存了引用的堆内存空间的地址)
(2)堆内存空间:保存每个对象的具体属性内容。
(3)全局数据区:保存static 类型的属性
(4)全局代码区:保存所有的方法定义
一、从数组角度理解内存分配
拿数组操作来说,在栈内存中保存的永远是数组的名称,只开辟了栈内存空间的数组是永远无法使用的,必须有指向的堆内存才可以使用,要想开辟新的堆内存就必须使用new关键字。
这也就解释了为什么对于数组的声明都要写上一个“null”?
int score[] = null;
score = new int[3]
// 或者:int score[] = new int[3];
因为数组属于引用数据类型,对于引用数据类型来说,其默认值就是null,表示暂时没有指向任何的内存空间
比如:
这里一个数组在开辟了堆内存之后,将在堆内存中保存数据,并将堆内存的操作地址给了数组名称score
此时也只是将堆内存的使用权交给了对应的栈内存空间,而一个堆内存空间可以被多个栈内存空间指向
比如一个人可以有多个名字,人就相当于堆内存,名字就相当于栈内存
二、从字符串角度来理解内存分配
public class Test{
public static void main(String[] args) {
String str1 = "hello";
String str2 = new String("hello");
String str3 = str2;
System.out.println("str1 == str2 -->" + (str1==str2));
System.out.println("str2 == str3 -->" + (str2==str3));
}
}
- 4
- 5
- 6
- 7
- 8
- 9
由结果可知,虽然程序String中的内容都是一样的,但是比较结果却不一致。
这是因为==
使用地址值进行比较的
从图中我们可知,每个 String 对象的内容实际上都是保存在堆内存之中的,而且堆中的内容也是相同的。但是对 str1 和 str2 来说,内容分别保存在不同的空间,所以即使内容相同,地址的值也是不同的
一个字符串就是一个 String 类的匿名对象,而如果使用 new 关键字,不管如何都会开辟一个新的空间,此空间的内容还是 hello。所以String str = new String("hello")
实际上是开辟了两个内存空间
匿名对象就是已经开辟堆内存空间并可以直接使用的对象。
因此当我们对于字符串进行操作时,一般采用直接赋值的方法完成,而不考虑采用构造方法的方式完成