要说Java中的栈,堆,方法区和常量池就要提到HotSpot,HotSpot是Sun JDK 和 Open JDK中所带的虚拟机。
(Sun JDK 和 Open JDK除了注释不同,代码实现基本上是一样的)
Stack(栈):分为VM Stack(虚拟机栈)和Native Method Stack(本地方法栈),不过HotSpot虚拟机直接把本地方法栈和虚拟机栈合二为一了。
虚拟机栈: 线程私有的, 描述的是Java方法执行的内存模型,方法调用的同时创建一个栈帧(储存局部变量表,操作数栈,方法出口等等),每个方法的调用直到执行完成对应的是栈帧在虚拟机中入栈和出栈的过程。
局部变量表(通常说的栈其实是栈里面的局部变量表):存放基本数据类型变量和对象的引用(所需内存在编译时期完成分配,方法运行时期不改变局部变量表大小,四个字节占用一个局部变量空间)
栈中的数据可以共享,例如:int a=3; int b=3;
编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着 处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。这时,如果再令 a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不 会影响到b的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译 器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。
包装类数据,如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中,Java用new()语句来显示地告诉编译器,在运行时才根据需要动态创建,因此比较灵活,但缺点是要占用更多的时间。
"==" 比较的是对象的地址,也就是是否是同一个对象;
"equal" 比较的是对象的值。
int 变为Integer 时,如果值在-128~127之间 则不会创建新的integer对象 储存常量池中,这么做的目的是提高效率.
Heap(堆):
Java堆是被所有线程共享的一块区域,在虚拟机启动时创建 ,此内存的唯一目的就是存放对象实例和数组,同时也是GC管理的主要区域。
分为新生代(Eden Survivor Survivor8:1:1)和老年代,Java堆可以处于物理上不连续的内存空间中,只要逻辑连续即可。
方法区:
运行时常量池:方法区的一部分
字面量:如文本字符串,声明为final的常量值等。
public stick final int i =3;
String s="abc";
符号引用:类和接口的全限定名、字段的名称和描述符、方法的名称和描述符
String 是一个特殊的包装类数据。即可以用String str = new String("abc");的形式来创建,也可以用String str = "abc";的形式来创建
(1)String str = "abc"创建对象的过程
1 首先在常量池中查找是否存在内容为"abc"字符串对象
2 如果不存在则在常量池中创建"abc",并让str引用该对象
3 如果存在则直接让str引用该对象
String str1 = "abc"; String str2 = "ab" + "c"; str1==str2是ture
是因为String str2 = "ab" + "c"会查找常量池中时候存在内容为"abc"字符串对象,如存在则直接让str2引用该对象,显然String str1 = "abc"的时候,上面说了,会在常量池中创建"abc"对象,所以str1引用该对象,str2也引用该对象,所以str1==str2
String str1 = "abc"; String str2 = "ab"; String str3 = str2 + "c"; str1==str3是false ---------//可参考Java编程思想第四版P284,285
是因为String str3 = str2 + "c"涉及到变量(不全是常量)的相加,所以会生成新的对象,其内部实现是先new一个StringBuilder,然后 append(str2),append("c");然后让str3引用toString()返回的对象