Java基礎11 物件引用
我們之前一直在使用“物件”這個概念,但沒有探討物件在記憶體中的具體儲存方式。這方面的討論將引出“物件引用”(object reference)這一重要概念。
物件引用
我們沿用之前定義的Human類,並有一個Test類:
= Human(160 Human(.height = growHeight(.height = .height +
外部可以呼叫類來建立物件,比如上面在Test類中:
Human aPerson = new Human(160);
建立了一個Human類的物件aPerson。
上面是一個非常簡單的表述,但我們有許多細節需要深入:
- 首先看等號的右側。 new是在記憶體中為物件開闢空間。具體來說,new是在記憶體的 堆(heap)上為物件開闢空間。這一空間中,儲存有物件的資料和方法。
- 再看等號的左側。aPerson指代一個Human物件,被稱為 物件引用(reference)。實際上,aPerson並不是物件本身,而是類似於一個指向物件的指標。aPerson存在於記憶體的 棧(stack)中。
- 當我們用等號賦值時,是將右側new在堆中建立物件的地址賦予給物件引用。
這裡的記憶體,指的是JVM (Java Virtual Machine)虛擬出來的Java程式記憶體空間。記憶體的堆和棧概念可參考 Linux從程式到程式。
物件引用
棧的讀取速度比堆快,但棧上儲存的資料受到有效範圍的限制。在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
引用,物件
被垃圾回收的條件
引數: 值傳遞
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31543790/viewspace-2664317/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Java基礎-物件導向基礎Java物件
- [Java基礎]Class物件Java物件
- JavaScript 基礎 (二) - 引用資料型別 (物件)JavaScript資料型別物件
- JAVA(一)JAVA基礎/物件導向基礎/高階物件導向Java物件
- JAVA物件導向基礎Java物件
- Java基礎-面相物件篇Java物件
- Java基礎| 類和物件Java物件
- 【Java 基礎】——物件導向Java物件
- Java基礎 --- 物件導向Java物件
- Java物件及物件引用變數Java物件變數
- java中的引用物件Java物件
- java基礎二:物件導向Java物件
- JAVA基礎之物件的排序Java物件排序
- 基礎篇:JAVA引用型別和ThreadLocalJava型別thread
- JAVA 物件引用,以及物件賦值Java物件賦值
- Java-基礎語法20:Lambda&方法引用Java
- 【Java基礎】物件導向開發Java物件
- 理解Java中物件基礎Object類Java物件Object
- (Java筆記)物件導向基礎Java筆記物件
- Java面試之基礎題---物件ObjectJava面試物件Object
- 【Java基礎】建立和銷燬物件Java物件
- Java之IO流基礎流物件Java物件
- 【Java基礎】--再談物件導向Java物件
- JAVA物件導向基礎--異常Java物件
- [Java基礎]物件的生命週期Java物件
- JAVA物件導向基礎--物件導向介紹Java物件
- 夯實Java基礎系列1:Java物件導向三大特性(基礎篇)Java物件
- 【重溫基礎】11.Map和Set物件物件
- java基礎學習之五:引用資料型別Java資料型別
- Java基礎系列(七):物件與類(下)Java物件
- JAVA_基礎IO流物件流(三)Java物件
- Java 基礎(一)重新理解物件導向Java物件
- java基礎 - 物件導向三大特性Java物件
- Java基礎 --- 物件導向綜合訓練Java物件
- Java基礎01 從HelloWorld到物件導向Java物件
- java基礎學習之一:物件和類Java物件
- 【web前端基礎 | JS基礎】物件Web前端JS物件
- Java基礎11---eclipse和APIJavaEclipseAPI