宏观来看
1.堆栈都是一种数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除。
要点:堆,顺序随意。栈,后进先出(Last-In/First-Out)。
2.堆和栈的区别可以用如下的比喻来看出:使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。
3.在java中方法里定义的变量,存储在栈内存,当方法结束时,自动销毁。 而new的对象是存储在堆内存里的,不会随方法结束而销毁,除非没有被另外的引用变量引用,会在被JVM在适当的时候回收。
微观来看
栈内存:
在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。
栈内存主要存放的是基本类型类型的数据,
如( int, short, long, byte, float, double, boolean, char) 和对象句柄。
并没有有String基本类型、
在栈内存的数据的大小及生存周期是必须确定的、
其优点是寄存速度快、栈数据可以共享、缺点是数据固定、不够灵活。
栈的共享:
String a = "abc";
String b = "abc";
System.out.println(a==b);
结果为true 这就说明了a b其实指向同一个值
注意,我们这里并不用a.equals(b);的方式,因为这将比较两个字符串的值是否相等。==号,根据JDK的说明,只有在两个引用都指向了同一个对象时才返回真值。而我们在这里要看的是,a与b是否都指向了同一个对象。
结果说明,JVM创建了两个引用a和b,但只创建了一个对象,而且两个引用都指向了这个对象。
首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有abc这个值,如果没找到,就将abc存放进来,然后将a指向abc。接着处理String b = "abc";在创建完b的引用变量后,因为在栈中已经有abc这个值,便将b直接指向abc。这样,就出现了a与b同时指向abc 特别注意的是,这种字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状态,那么另一个对象引用变量也即刻反映出这个变化。相反,通过字面值的引用来修改其值,不会导致另一个指向此字面值的引用的值也跟着改变的情况。如上例,我们定义完a与b的值后,再令a=abcd;那么,b不会等于abcd,还是等于abc。在编译器内部,遇到a= abcd;时,它就会重新搜索栈中是否有abcd的字面值,如果没有,重新开辟地址存放abcd的值;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。
堆内存:
堆内存用来存放所有new 创建的对象和 数组的数据、
String a = new String ("abc");
String b = "abc";
System.out.println(a==b); //False
String a = new String ("abc");
String b = new String ("abc");
System.out.println(a==b); //False
创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。以上两段代码说明,只要是用new()来新建对象的,都会在堆中创建,而且其字符串是单独存值的,即使与栈中的数据相同,也不会与栈中的数据共享。