堆栈常量池

堆栈常量池详解+例子

转自:http://www.iteye.com/topic/634530

一:概述
  1. 寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制.

  2. 栈(stack):存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。

  3. 堆(heap):存放所有new出来的对象。

  4. 静态域:存放静态成员(static定义的)

  5. 常量池:存放字符串常量(String)和基本类型常量(public static final)

  6. 非RAM存储:硬盘等永久存储空间

存放基本数据类型变量数据和对象的 “引用”,对象本身不存在这个里面。

常量池:

像int i=1中的1就不放在常量池中,因为这个1不是常量属于变量。

像public static final int i=1中的1就放在这个常量池中。

二:初步理解(可以先看最下面的几个性质)
String类型
String s1 = "china";  
String s2 = "china";  
String s3 = "china";  
String ss1 = new String("china");  
String ss2 = new String("china");  
String ss3 = new String("china");  

自己先别看图,想一下,图像是什么。

栈中有几个对象

堆中有几个对象

常量池中有几个对象

特别的还要注意有几个箭头!

img

栈:所有数据和对象的引用都放在栈中,所以六个String产生六个名字在栈中。

堆:只要是new出来的都在栈中存储,前三个没有new只有后面三个在堆中存在

常量池:所有的字符串类型和基本数据类型都在这个里面存着,并且相同的不会重复存储。

String ss1 = new String(“china”); 整体介绍

对于通过new产生一个字符串(假设为”china”)时,会先去常量池中查找是否已经有了”china”对象,如果没有则在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中此”china”对象的拷贝对象。这也就是有道面试题:String s = new String(“xyz”);产生几个对象?一个或两个,如果常量池中原来没有”xyz”,就是两个。

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

img

对于基础类型的变量和常量:变量和引用存储在栈中,常量存储在常量池中。

如int a = 3; 这里的a是一个指向int类型的引用,指向3这个字面值。这些字面值的数据,由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出后,字段值就消失了),出于追求速度的原因,就存在于栈中。

##### 隆重介绍–引用类型######
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 change1(int i){  
        i = 1234;  
    }  

}

对于以上这段代码,date为局部变量,i,d,m,y都是形参为局部变量,day,month,year为成员变量。下面分析一下代码执行时候的变化:

  1. main方法开始执行:int date = 9;
    date局部变量,基础类型,引用和值都存在栈中。
  2. Test test = new Test();
    test为对象引用,存在栈中,对象(new Test())存在堆中
  3. test.change(date);
    i为局部变量,引用和值存在栈中。当方法change执行完成后,i就会从栈中消失。
  4. BirthDate d1= new BirthDate(7,7,1970);
    d1为对象引用,存在栈中,对象(new BirthDate())存在堆中,其中d,m,y为局部变量存储在栈中,且它们的类型为基础类型,因此它们的数据也存储在栈中。day,month,year为成员变量,它们存储在堆中(new BirthDate()里面)。当BirthDate构造方法执行完之后,d,m,y将从栈中消失。
  5. main方法执行完之后,date变量,test,d1引用将从栈中消失,new Test(),new BirthDate()将等待垃圾回收.

img

三:性质介绍
堆和栈的性质
  • 栈:

    • 由编译器自动分配释放 ,存放函数的参数值,局部变量的值
    • 优点是存取速度很快,仅次于CPU中的寄存器
    • 缺点是存在栈中的数据大小与生存期必须是确定的、
    • 栈中的数据可以共享(见下面详细介绍)
  • 堆:

    • Java的垃圾回收器自动收走这些不再使用的数据
    • 优点是动态的分配内存大小(因为是存储new 出来的数据的)
    • 缺点是运行时需要动态分配内存,所以存取速度慢
栈的共享性

存在栈中的数据可以共享

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;那么,b不会等于4,还是等于3。在编译器内部,遇到a=4;时,它就会重新搜索栈中是否有4的字面值,如果没有,重新开辟地址存放4的值;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。

上面这个例子很容易与引用类型的混淆:

假定两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状态,那么另 一个对象引用变量也即刻反映出这个变化。

成员变量和局部变量

img

记住一点:栈里面是用完就删!而堆是全局的!

  • 上面的局部变量放在栈中
  • 成员变量中的实例变量放在堆中

类对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状态,那么另 一个对象引用变量也即刻反映出这个变化。

成员变量和局部变量

[外链图片转存中…(img-JtiCFBij-1640593655375)]

记住一点:栈里面是用完就删!而堆是全局的!

  • 上面的局部变量放在栈中
  • 成员变量中的实例变量放在堆中
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值