数据存储在哪里,堆?栈?

thinking in java 读书笔记(感悟);
页码:P9 (想看书上怎么讲的。自行翻看 P22 页)

写于:2018年3月29日21:09:48

作者:淮左白衣

目录


先说明下一些名字的概念,以前我曾以为寄存器是内存;(大笑。。。。)

寄存器

寄存器,是最快的存储区域了,因为寄存器在CPU的内部!近水楼台先得月嘛,执行效率杠杠的;千万不能因为它是速度快,以为这货就是内存,笔者以前就是因为它快,在学java的时候,老师讲过内存读取是很快的,快过硬盘的;就以为金寄存器是内存。。。


栈,位于RAM中。RAM怎么说呢,是随机访问存储器的简写;懂了吗?反正我当初不懂什么是随机访问存储器,又跑去百度随机访问存储器;得出一个结论:RAM可以不严谨的称为内存;之所以不严谨,是因为RAM也不是内存,只是内存中一个至关重要的存储单元;姑且,称之为内存吧;

栈的访问速度非常快,仅次于寄存器 ;

栈中的数据是共享的!这句话,请记住!


堆,同样位于内存中;


常量池

存放那些实例不可改变的量;比如字符串,这里不是所有的字符串都在这存放在这里;对了,多说一句,基本类型的包装类,也是不可改变的 ;


硬盘

持久化存储


上面的废话,终于讲完了,进入正题!我们平时写的代码,那些变量、对象这些数据存放在哪里?

场景(int a = 4 ; 背后的故事)

int a = 3 ;
int b = 3 ;
a = 4 ;

String str1 = "淮左白衣" ;
String str2 = new String("淮左白衣");

请问这些代码的背后发生了什么?或者它们在内存中怎么存储的?

——————————— 我一句一句代码讲 ———————————-

int a = 3 ;

在栈中开辟一片空间,存储 3 这个字面值;然后继续在栈中开辟空间,存储引用a ,并把引用a 指向 3 那片地址 ;

int b = 3 ;

先在栈中查找是否有 3 这个字面值存在,如果有,就直接使用(栈中的数据是共享的);如果没有,则开辟空间,存储 3 这个字面值 ;

在我们这里是有的,因此只会在栈中开辟存储引用 b 的空间;然后把引用b指向 3 那片地址 ;

a = 4 ;

同样,先在栈中查找是否有 4 这个字面值存在,如果有,就直接使用;如果没有,则开辟空间,存储 4 这个字面值 ;

在我们这里,是没用的,因此,先在栈中开辟空间,存储字面值 4 ,然后把 引用 a ,重新指向存储字面值 4 的那片地址 ;这里注意引用 b 的指向的 3 是不受影响的 ;

下面的两句代码,一句代码,就能讲一个故事了,因此,另起段落写 ;


String str1 = “淮左白衣” 背后的故事

第一步:首先在字符串常量池中查找是否有 “淮左白衣” 这个字符串;如果没有的话,则在常量池中,创建一个 “淮左白衣” 的字符串,然后,划重点,这一步网上许多资料都没有说出来,在 中,创建一个字符串对象,但是这个字符串对象的字面值,是一个引用,而不是字符串,这个引用,就指向常量池中的那个 “淮左白衣” 这个字符串对象,常量池中的“淮左白衣” 对象,同样也持有堆上的那个字符串对象的引用 ;在栈中创建一个引用 str ,引用指向常量池中的对象持有的堆上的对象的地址

第二步:如果有的话,则直接在栈中创建引用 str ,然后让引用,指向常量池中那个“淮左白衣”对象所持有的引用 ;


String str1 = new String(“淮左白衣” ) ; 这背后的故事又是什么呢

第一步:先去常量池中寻找是否有“淮左白衣”这个字符串对象,如果有的话,则在堆中,拷贝一个这个对象 ;然后把堆中的这个对象的地址,返回给栈中的 str ;

第二步:如果,常量池中没有“淮左白衣”这个对象,则先在常量池中创建一个“淮左白衣”字符串对象;然后,去堆中,拷贝一个这个对象;后把堆中的这个对象的地址,返回给栈中的 str ;


故事讲到这里,已然完结,谢幕吧!(掌声、鲜花。。。)


ちょっと待って

等一下,还有一些东西忘记说了 ;

String str1 = "abc" ;
String str2 = "ab" + "c" ;
String str3 = new String("ab") + "c" ;

上面的3个引用,使用“ == ” 符号来运算;
str1 == str2 ; true
str1 == str3 ; false
str2 == str3 ; false

原因是:

String str2 = "ab" + "c" ;

对于这样的代码,编译期间,编译器会进行优化,因为“ab”、“c” 都是确定的值,编译器会自动将它们优化为:

String str1 = "abc" ;

因此,str1 == str2 是true ;而对于 new String(“ab”) 这样的东西,编译期间,无从得知,它们具体是什么,也就无法优化了 ,只能在堆中创建对象了 ;


备注

常量池有许多,什么Integer、Long、Strng啊等等,都有自己的常量池;文中所说的常量池,均指字符串常量池 ;*

posted @ 2018-03-29 21:12  Yiaz  阅读(416)  评论(0编辑  收藏  举报