java十分钟速懂知识点——引用
一、由健忘癥引起的問題
? ? 今天閑來沒事在日志中瞟見了個OutOfMemoryError錯誤,不由得想到前一段時間看到一篇面經(jīng)里問到Java中是否有內(nèi)存泄露,這個很久以前是留意過的,大體記得內(nèi)存溢出和內(nèi)存泄露是不同的,至于各自都有哪些情況,那個...額....忘了...。好吧,記憶力一向不好,忘就忘了,那就再總結(jié)一遍吧。翻了下收藏的博客,回顧了下便是想起了了~.~??雌饋硪磺泻苊篮?#xff0c;但是其中的一個例子突然使我困惑了:
public class TestDemo {static Test[] tests = new Test[3];public static void main(String[] args) {Test t = new Test("test1");tests[0] = t;//將t置為null,看起來似乎我們已經(jīng)釋放創(chuàng)建的對象,當(dāng)下次gc時其將被回收t = null;//那么我們打印下test[0]看看System.out.println(tests[0]);} } ? ? 這是個示例內(nèi)存泄露的例子,該例子十分典型,幾乎所有內(nèi)存泄露的示例都與此類似,作為javaer往往覺得理所應(yīng)當(dāng)。然而作為一個學(xué)習(xí)C++入行(學(xué)的很爛),并一直把引用當(dāng)指針看的javaer不免覺得有些疑惑:t是對象的引用,這里可以看做指向?qū)ο蟮闹羔?#xff0c;那么test[0]=t,按理說應(yīng)該是把t指針賦值給test[0],算是地址傳遞吧,那個t指向null之后,test[0]應(yīng)該也指向null了啊。
? ? 看起來似乎有點道理,然而當(dāng)了解了java的引用之后,發(fā)現(xiàn)吧指針等同于引用是有一些問題的。
二、引用到底是什么
? ? java中的引用到底是什么呢,簡單點說,引用就是存在棧區(qū)的一種特定類型的數(shù)據(jù),其存儲著對象實例在堆區(qū)的地址,其特點如下:
- 本身是一種數(shù)據(jù)類型,存儲在棧區(qū)
- 其值存儲著實例對象在堆區(qū)的虛擬地址(注意,是虛擬地址,并不是實際內(nèi)存地址,就如同圖書館里的索引號,不經(jīng)過轉(zhuǎn)換你并不知道書的實際位置)
- 對象在創(chuàng)建未賦值時(無實例),引用會指向null
- java中參數(shù)傳遞只有值傳遞一種,所謂的引用傳遞傳遞的是引用中存儲的值
? ? 從定義看起來似乎還是區(qū)分不出來引用到底和指針有什么區(qū)別,那么請注意上邊紅字,java為了屏蔽對內(nèi)存直接操作,對對象的實際內(nèi)存地址進行了包裝,從而使引用中的值只能用來找對象,而無法操作內(nèi)存。這一點正是和指最大不同,C++中的指針就是一個真實的內(nèi)存地址,可以通過該地址把內(nèi)存玩出十八般花樣。這點也說明了我們常常把引用傳遞當(dāng)成地址傳遞是錯誤的(雖說實際效果差不多)。
三、上邊的例子到底發(fā)生了什么
? ? 好吧,看了上邊一坨也許你并看不出個什么,也許本身這塊有點繞,也許我說的不清楚,那么我們不如直接畫圖說明上邊那個例子到底發(fā)生了什么(圖示畫的不一定和實際完全一致,只為說明問題),說不定你就明白了:
? ? tests由于是靜態(tài)變量,在類加載完就已經(jīng)實例化了,其在堆內(nèi)存中分配了長度為3的空間,不過值都為null。在創(chuàng)建t之后,t指向了堆內(nèi)存中的對象:
? ? tests[0]=t,這就是我們理解錯誤的地方,這一步test[0]并不是指向t,而是t把Test實例的地址直接賦值給了tests[0],因此tests[0]同樣指向Test實例,這和t已經(jīng)沒有任何關(guān)系了。
? ? 其實從上圖我們就應(yīng)該理解了,t=null之后,其實只是斬斷了t和Test實例的關(guān)系,并沒有改變Test到tests的依賴,從而gc并不會回收Test,這樣就造成了邏輯上的內(nèi)存泄露(為啥說邏輯上,因為明明就是你讓tests還存著Test呢,只是你自以為是的以為釋放了,當(dāng)然,這種意義的泄露和C++所說的內(nèi)存泄露很不同)。
四、只為了結(jié)尾不突兀
? ? 本來是想整理篇內(nèi)存溢出和內(nèi)存泄露的,順便寫下這塊,但是發(fā)現(xiàn)并不是太好說清楚,就單寫了。好了,就這樣吧,原來JVM學(xué)習(xí)總結(jié)系列寫了一半扔那了,現(xiàn)在發(fā)現(xiàn)還是挺有意思的,有空接著寫吧。
轉(zhuǎn)載于:https://www.cnblogs.com/good-temper/p/4916063.html
總結(jié)
以上是生活随笔為你收集整理的java十分钟速懂知识点——引用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Servlet和JAVA BEAN 分析
- 下一篇: 【宋红康学习日记3】运算符