数据存储在哪里,堆?栈?
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啊等等,都有自己的常量池;文中所说的常量池,均指字符串常量池 ;*