一、定義
引用類型表示你操作的數據是同一個,也就是說當你傳一個參數給另一個方法時,你在另一個方法中改變這個變量的值,那么調用這個方法是傳入的變量的值也將改變。
值類型表示復制一個當前變量傳給方法,當你在這個方法中改變這個變量的值時,最初生命的變量的值不會變。
值類型
也就是基本數據類型 基本數據類型常被稱為四類八種。
四類八種:
整型(4種):byte(1 byte)、short(2 byte)、int(4 byte)、long(8 byte)
浮點型(2種):float(4 byte)、double(8 byte)
字符型(1種):char(2 byte)
邏輯型(1種):boolean
引用類型
除了八種基本數據類型外,其他所有的類型都稱為引用類型(數組、類、接口、字符串等)
在弄清楚值類型與引用類型之后,最后一點就是值傳遞與引用傳遞,這才是關鍵
值傳遞
基本數據類型賦值都屬于值傳遞,值傳遞傳遞的是實實在在的變量值,是傳遞原參數的拷貝,值傳遞后,實參傳遞給形參的值,形參發生改變而不影響實參。
引用傳遞
引用類型之間賦值屬于引用傳遞。引用傳遞傳遞的是對象的引用地址,也就是它的本身(自己最通俗的理解)。引用傳遞:傳的是地址,就是將實參的地址傳遞給形參,形參改變了,實參當然被改變了,因為他們指向相同的地址。
引用和我們的指針差不多,但是它不又不需要我們去具體的操作。
二、區別
三、內存分配
值類型
值類型(value type)的數據存放在棧內的一個變量中。即是在棧中分配內存空間,直接存儲所包含的值,其值就代表數據本身。
但是也有特殊情況,如果某個類的實例有個值類型的字段,那么實際上該字段會和類實例保存在同一個地方,即堆中。不過引用類型的對象總是存儲在堆中;如果一個結構的字段是引用類型,那么只有引用本身是和結構實例存儲在一起的(在棧或堆上,視情況而定)。
值類型的數據具有較快的存取速度。
引用類型
引用類型(reference type)的數據并不駐留在棧中,而是存儲于堆中。即是在堆中分配內存空間,存儲所包含的值,而棧中存儲的是指向該值的地址。當訪問一個具有引用類型的數據時,需要到棧中檢查變量的內容,該變量引用堆中的一個實際數據。引用類型的數據比值類型的數據具有更大的存儲規模和較低的訪問速度。
注:
棧(stack)是一種后進先出的數據結構。在內存中,變量會被分配在棧上來進行操作。堆(heap)是用于為類型實例(對象)分配空間的內存區域,在堆上創建一個對象,會將對象的地址傳給棧上的變量(反過來叫變量指向此對象,或者變量引用此對象)。
值類型總是分配在它聲明的地方:作為字段時,跟隨其所屬的變量(實例)存儲;作為局部變量時,存儲在棧上。
值類型在內存管理方面具有更好的效率,并且不支持多態,適合用做存儲數據的載體;
引用類型支持多態,適合用于定義 應用程序的行為。
四、回收機制
當一個堆內存中的對象沒有被棧內存中表示地址的值“引用”時,這個對象就被稱為垃圾對象,它無法被使用但卻占據著內存中的區域,好比這樣:
String s = new String("person");
s = new String("man");
s本來是指向堆內存中值為person的對象的,但是s突然討厭person了,它指向了堆內存中的man對象了,person就像一個孤兒一樣被s遺棄了,但是person比孤兒還要慘,因為沒有什么能找的到它,除了位高權重的‘垃圾回收器’,不過被當官的找到往往沒什么好事,尤其是這個‘垃圾回收器’,它會豪不留情把‘垃圾’們清理走,并且無情的銷毀,以便釋放內存。
Java中有垃圾回收機制,棧內存中的變量隨著方法的結束內存自然銷毀了,而用引用類型的時候,當方法結束的時候,這個對象可能被另一個引用類型所應用,不會銷毀,只有當一個對象沒有任何引用變量引用的時候,垃圾回收機制才會回收。
五、為什么Java中數據的存放有堆和棧之分?
答:當一個方法執行時,每個方法都會建立自己的內存棧,在這個方法內定義的變量將會逐個放入這塊棧內存里,隨著方法的執行結束,這個方法的內存棧也將自然銷毀了。因此,所有在方法中定義的變量都是放在棧內存中的;當我們在程序中創建一個對象時,這個對象將被保存到運行時數據區中,以便反復利用(因為對象的創建成功通常較大),這個運行時數據區就是堆內存。堆內存中的對象不會隨方法的結束而銷毀,即使方法結束后,這個對象還可能被另一個引用變量所引用(方法的參數傳遞時很常見),則這個對象依然不會被銷毀。只有當一個對象沒有任何引用變量引用它時,系統的垃圾回收機制才會在合適的時候回收它。
六、裝箱與拆箱
裝箱:
裝箱就是值類型到引用類型的轉化過程。將一個值類型變量裝箱成一個引用類型變量,首先會在托管堆上為新的引用類型變量分配內存空間,然后將值類型變量拷貝到托管堆上新分配的對象內存中,最后返回新分配的對象內存地址。
拆箱:
裝箱操作是可逆的,所以還有拆箱操作。拆箱操作獲取只想對象中包含值類型部分的指針,然后由程序員手動將其對應的值拷貝給值類型變量。