堆和栈都是Java用来在RAM中存放数据的地方。
堆
(1)Java的堆是一个运行时数据区,类的对象从堆中分配空间。这些对象通过new等指令建立,通过垃圾回收器来销毁。
(2)堆的优势是可以动态地分配内存空间,需要多少内存空间不必事先告诉编译器,因为它是在运行时动态分配的。但缺点是,由于需要在运行时动态分配内存,所以存取速度较慢。
栈
1)栈中主要存放一些基本数据类型的变量(byte,short,int,long,float,double,boolean,char)和对象的引用。
(2)栈的优势是,存取速度比堆快,栈数据可以共享。但缺点是,存放在栈中的数据占用多少内存空间需要在编译时确定下来,缺乏灵活性。
举例说明栈数据可以共享
int a = 3;
int b = 3;
编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。接着处理int b = 3;在创建完b的引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。这样,就出现了a与b同时均指向3的情况,即共享了3这个栈数据。.
java的八种引用类型(Byte Short、Integer、Long、Character、Boolean、Float、Double),除Float及Double以外,其它六种都实现了常量池,但是他们只在大于等于-128且小于等于127时才能使用常量池,如果不在此范围内,则会new一个出来,保存在堆内存中。
Integer i1 = 100, i2 = 100, i3 = 150, i4 = 150;
//涉及到IntegerCache 这个内部类的问题
// true 如果整型字面量的值在-128到127之间,那么不会new新的Integer对象,而是直接引用
System.out.println(i1 == i2);
// false 生成两个对象.
System.out.println(i3 == i4);
Long f1 = 100l, f2 = 100l, f3 = 150l, f4 = 150l;
//涉及到Cache 这个内部类用作缓存的问题
System.out.println(f1 == f2); // true 如果Long字面量的值在-128到127之间而是直接引用
System.out.println(f3 == f4); // false 生成两个对象.
特别注意的是,这种字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状态,那么另一个对象引用变量也即刻反映出这个变化。相反,通过字面值的引用来修改其值,不会导致另一个指向此字面值的引用的值也跟着改变的情况。如上例,我们定义完a与b的值后,再令a=4;那么,b不会等于4,还是等于3。在编译器内部,遇到a=4;时,它就会重新搜索栈中是否有4的字面值,如果没有,重新开辟地址存放4的值;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。
!
代码一:
public class Demo {
public static void main(String[] args) {
String s1 = "china";
String s2 = "china";
String s3 = "china";
String ss1 = new String("china");
String ss2 = new String("china");
String ss3= new String("china");
}
}
思考:分布情况会怎样?
s1、s2、s3都是基本类型的局部变量,
ss1、ss2、ss3都是String对象的引用,
所以都在栈区
而"china"是常量,
所以放在常量区
而三个new的对象,
自然就放在堆区
代码二:
class BirthDate{
private int day;
private int month;
private int year;
public BirthDate(int d, int m, int y) {
day = d;
month = m;
year = y;
}
//省略get.set方法.
}
public class Test{
public static void main(String[] arg) {
int date = 9;
Test test = new Test();
test.change(date);
BirthDate d1= new BirthDate(7,7,1970);
}
public void change(int i){
i = 1234;
}
}
思考:内存如何分布?
从执行代码部分看,
date, test, i, d1, d,m、y.
都属于基本类型的局部变量, 因此都分配到栈区。
而Test(),Birthdate()两个都是new出来的对象,因此都放在堆区。