java 存储方式详解及示例

来源:互联网 发布:mac网站老是跳转 编辑:程序博客网 时间:2024/06/05 04:37

java的数据存储区域有六种:

(1)寄存器:
寄存器是最快的存储区,这是因为它位于不同于其它存储区额地方——处理器的内部。但是寄存器的数量十分有限,所以是由编译器根据需求进行自动分配的,不能由程序来控制。
(2)栈(Stack):
栈的速度仅次于寄存器,因为它位于RAM中。栈中存放基本数据类型的变量数据和对象的引用。由于栈中需要频繁地上下移动指针,此时便需要确切地知道每个对象的生命周期,这一约束便限制了程序的灵活性,所以对象的本身并不会放在栈中,而是会放在堆中,因为堆中的对象是由垃圾回收器来回收的,具有比较大的灵活性;
(3)堆(Heap):
位于通用的内存池(也位于RAM区),用于存放所有的对象(简单讲就是new出来的对象);
(4)静态域:
存放所有的静态成员(static变量);
(5)常量池:
存放字符串常量(String变量,因为String是immutable)和基本数据类型常量(final int等变量)。有时在嵌入式系统中,常量本身会和代码部分相对独立开来,这样的情况下,可以将其存放在ROM中;
(6)非RAM存储:
硬盘等永久存储区域,此时数据是完全存活于程序以外的。

针对比较常用的栈,堆和常量池,需要理解清楚。对于栈和常量池中的数据是共享的,而堆中的数据是不可共享额。栈中的数据项的生命周期是可以且必须是确定的,所以当没有引用指向该数据时,这个数据项就会从栈中消失。而堆中的对象则是有垃圾回收器来负责回收的,因此其生命周期不需要确定,具有比较大的灵活性。

针对常用类型的详细理解:

对于字符串,其对象的引用存储在栈中,但是如果是在编译期间就已经确定的(即直接是双引号赋值),那就会存在常量池中,而如果是在运行期间(即new出来的)才能确定的就存储在堆中。在常量池中,始终只会有一份值,而在堆中,可能会有多个。

示例:

String s1 = “china”;String s2 = “china”;String s3 = “china”;String ss1 = new String(“china”);String ss2 = new String(“china”);String ss3 = new String(“china”);

对于这段代码,其存储结构是这样的:
这里写图片描述

这边黄色的箭头意义: 对于通过new产生的字符串(假设为“china”),首先会去常量池中查找是否存在这样的字符串“china”,如果没有就会在常量池中创建一个此字符串对象,然后再在堆中创建一个常量池中该“china”对象的拷贝对象。所以对于一道面试题:String s = new String(“x”);产生几个对象?答案是一个或者两个,因为当常量池中有值为“x”的对象,那么只会在堆中创建该对象的一个拷贝对象,如果没有的话,那就是先在常量池中创建一个值为”x”的对象,然后在堆中继续创建该对象的一个拷贝对象,就是一共创建了两个对象。

对于基础数据类型的变量和常量
变量及其引用均存储在栈中,常量存储在常量池中。

示例:

int i1 = 9;int i2 = 9;int i3 = 9;static final int INT1 = 9;static final int INT2 = 9;static final int INT3 = 9;

存储结构:
这里写图片描述

对于成员变量和局部变量
成员变量存储在堆中的对象里面(因为成员是属于某个对象的),由垃圾回收其负责回收;
局部变量存储在栈中,因为局部变量一般都是方法内部的形式参数,所以会随着方法的消失而消失。
示例:

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 args[]){              int date = 9;                   Test test = new Test();                           test.change(date);                   BirthDate d1= new BirthDate(7,7,1970);                     }                public void change(int i){                  i = 1234;              }  }

存储过程结构:
这里写图片描述

详细分析上述代码执行过程:
<1>. main方法开始执行 : int date = 9;
由于date是局部变量(出在main函数内,而非函数外&类中),且位基本数据类型,则引用(date)和数值(9)都在栈中;
<2>. Test test = new Test();
test位对象的引用,存在栈中,对象(new Test())存在堆中;
<3>. test.change(date);
观察change函数,i为局部变量,存在栈中,当change函数执行完毕,i从栈中消失;
<4>. BirthDate d1 = new BirthDate(7,7,1970);
d1为对象的引用,存在栈中,对象(new BirthDate())存在堆中,其中后面的d,m,y均为形式参数,属于局部变量,存在栈中,并且由于它们为基本数据类型,所以其数值也都存在栈中。而day,month,year是属于成员变量,它们则存储在堆中(其实是存在堆中的new BirthDate()对象),当执行完其构造方法后d,m,y会从栈中消失,而day,month,year则会伴随垃圾回收器回收new BirthDate()对象时才会一并被回收。
<5>. main方法执行完毕
date变量,test,d1引用都从栈中消失,new Test(),new BirthDate()对象将会等待垃圾回收器回收释放。

0 0
原创粉丝点击