咱們以前一直在使用「對象」這個概念,但沒有探討對象在內存中的具體存儲方式。這方面的討論將引出「對象引用」(object reference)這一重要概念。
html
咱們沿用以前定義的Human類,並有一個Test類:app
= Human(160 Human(.height = growHeight(.height = .height +
外部能夠調用類來建立對象,好比上面在Test類中:ide
Human aPerson = new Human(160);
建立了一個Human類的對象aPerson。 焦做國醫胃腸醫院怎麼坐車:http://jz.lieju.com/zhuankeyiyuan/37325304.htm函數
上面是一個很是簡單的表述,但咱們有許多細節須要深刻:post
首先看等號的右側。 new是在內存中爲對象開闢空間。具體來講,new是在內存的 堆(heap)上爲對象開闢空間。這一空間中,保存有對象的數據和方法。測試
再看等號的左側。aPerson指代一個Human對象,被稱爲 對象引用(reference)。實際上,aPerson並非對象自己,而是相似於一個指向對象的指針。aPerson存在於內存的 棧(stack)中。spa
當咱們用等號賦值時,是將右側new在堆中建立對象的地址賦予給對象引用。設計
這裏的內存,指的是JVM (Java Virtual Machine)虛擬出來的Java進程內存空間。內存的堆和棧概念可參考 Linux從程序到進程。指針
http://dalian.qd8.com.cn/yiyao/xinxi21_3709995.htmlcode
對象引用
棧的讀取速度比堆快,但棧上存儲的數據受到有效範圍的限制。在C語言中,當一次函數調用結束時,相應的棧幀(stack frame)要刪除,棧幀上存儲的參量和自動變量就消失了。Java的棧也受到一樣的限制,當一次方法調用結束,該方法存儲在棧上的數據將清空。在 Java中, 全部的(普通)對象都儲存在堆上。所以, new關鍵字的完整含義是, 在堆上建立對象。
基本類型(primitive type)的對象,好比int, double,保存在棧上。當咱們聲明基本類型時,不須要new。一旦聲明,Java將在棧上直接存儲基本類型的數據。因此,基本類型的變量名錶示的是數據自己,不是引用。
引用和對象的關係就像風箏和人。咱們看天空時(程序裏寫的),看到的是風箏(引用),但風箏下面對應的,是人(對象):
引用和對象分離;引用指向對象
儘管引用和對象是分離的,但咱們全部通往對象的訪問 必須通過引用這個「大門」,好比以 引用.方法() 的方式訪問對象的方法。在Java中,咱們不能跳過引用去直接接觸對象。再好比,對象a的數據成員若是是一個普通對象b,a的數據成員保存的是指向對象b的引用 (若是是基本類型變量,那麼a的數據成員保存的是基本類型變量自己了)。
在Java中,引用起到了指針的做用,但咱們不能直接修改指針的值,好比像C語言那樣將指針值加1。咱們只能經過引用執行對對象的操做。這樣的設計避免了許多指針可能引發的錯誤。
當咱們將一個引用賦值給另外一個引用時,咱們實際上覆制的是對象的地址。兩個引用將指向同一對象。好比 dummyPerson=aPerson;,將致使:
一個對象能夠有多個引用 (一我的能夠放多個風箏)。當程序經過某個引用修改對象時,經過其餘引用也能夠看到該修改。咱們能夠用如下Test類來測試實際效果:
public class Test { public static void main(String[] args) { Human aPerson = new Human(160); Human dummyPerson = aPerson; System.out.println(dummyPerson.getHeight()); aPerson.growHeight(20); System.out.println(dummyPerson.getHeight()); } }
咱們對aPerson的修改將影響到dummyPerson。這兩個引用實際上指向同一對象。
因此,將一個引用賦值給另外一個引用,並不能複製對象自己。咱們必須尋求其餘的機制來複制對象。
隨着方法調用的結束, 引用和 基本類型變量會被清空。因爲對象存活於堆,因此對象所佔據的內存不會隨着方法調用的結束而清空。進程空間可能很快被不斷建立的對象佔滿。Java內建有 垃圾回收(garbage collection)機制,用於清空再也不使用的對象,以回收內存空間。
垃圾回收的基本原則是,當存在引用指向某個對象時,那麼該對象不會被回收; 當沒有任何引用指向某個對象時,該對象被清空。它所佔據的空間被回收。
上圖假設了某個時刻JVM中的內存狀態。Human Object有三個引用: 來自棧的aPerson和dummyPerson,以及另外一個對象的數據成員president。而Club Object沒有引用。若是這個時候垃圾回收啓動,那麼Club Object將被清空,而Human Object來自Club Object的引用(president)也隨之被刪除。
垃圾回收是Java中重要的機制,它直接影響了Java的運行效率。我將在之後深刻其細節。
當咱們分離了引用和對象的概念後,Java方法的參數傳遞機制實際上很是清晰: Java的參數傳遞爲 值傳遞。也就是說,當咱們傳遞一個參數時,方法將得到該參數的一個拷貝。
實際上,咱們傳遞的參數,一個是基本類型的變量,另外一個爲對象的引用。
基本類型變量的值傳遞,意味着變量自己被複制,並傳遞給Java方法。Java方法對變量的修改 不會影響到原變量。
引用的值傳遞,意味着對象的地址被複制,並傳遞給Java方法。Java方法根據該引用的訪問將 會影響對象。
在這裏有另外一個值得一提的狀況: 咱們在方法內部使用new建立對象,並將該對象的引用返回。若是該返回被一個引用接收,因爲對象的引用不爲0,對象依然存在,不會被垃圾回收。
new
引用,對象
被垃圾回收的條件
參數: 值傳遞