有这么几种存储位置,速度逐级递减:
寄存器
栈内存
堆内存
静态存储
常量存储
寄存器是最快的保存区域,因为它位于和其他所有保存方式不同的地方:处理器内部。然而,寄存
器的数量十分有限,所以寄存器是根据需要由编译器分配。我们对此没有直接的控制权,也不可能在自己的
程序里找到寄存器存在的任何踪迹。静态存储和常量存储是存储使用static定义的各种静态数据和常量,字符串池也在这。
最重要的是栈内存和堆内存:
- 栈内存:存放基本数据类型(8种)和对象句柄(对象的引用,我喜欢叫对象句柄,类似于C语言中的指针)。栈指针向下移动则创建空间,向上移动则释放空间,速度几乎跟寄存器相当,贼快。栈内存还可以数据共享,比如说int a=1;int b=1;a创建一块保存着“1”的存储空间,当创建b时,b也需要“1”,那么栈内存就不会创建直接把a的地址给b,这么做的好处不用说是节约空间。
-
堆内存:存放使用new关键字创建的对象,Java中有垃圾回收机制,垃圾回收即对此部分进行回收(回收的是对象内存)。堆内存最吸引人的地方在于编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要
在堆里停留多长的时间。因此,用堆保存数据时会得到更大的灵活性。
了解这些信息就能想通学习Java.lang.String对象时碰到的让我晕乎的问题:
String a1 = "abc";
String a2 = "abc";
System.out.println(a1 == a2); //输出true
----------------------------------------
String a3 = new String("abc");
String a4 = new String("abc");
System.out.println(a3 == a4); //输出false
a1句柄创建时在字符串池中创建一个"abc",a2句柄想要一个"abc"常量时,直接把a1的地址给了a2,也就是说a1和a2是一模一样的,打印true;a3句柄使用new了一个String对象,保存在了堆内存中,a4句柄也使用new创建了一个String对象,也保存在了堆内存中,两个句柄分别指向了一个不一样的堆内存的地址,打印出false。
然而又能想到为什么在多次使用String字符串时使用StringBuilder或者StringBuffer来处理字符串了,如果要拼接字符串:
int a = 1;
String a1 = "hello" + a + "w" + a + "orld"....
使用这种方式拼接字符串,会在字符串池中创建多个对象,很浪费空间。
之前面试面试官问我:
String a = new String("123");
会创建几个对象,通过阅读Java编程思想,答案是两个对象(处在栈内存中的a句柄是变量,不属于对象,处在堆内存中的String对象,处在常量池中的"123")。
再列举几个例子:
String a = "123"+"456";//三个
String a1 = "123"; String a2 = "123"; //一个