java變量種類及存儲方式

變量種類:

  1. 全局變量(成員變量)
  2. 局部變量
  3. 靜態(tài)變量

變量解釋

1. 全局變量(成員變量):

1.全局變量定義在類中,在整個類中都可以被訪問
2.全局變量有默認(rèn)的初始化值
3.全局變量隨著對象的建立而建立,隨著對象的消失而消失,存在于對象所在的堆內(nèi)存

2. 局部變量:

1.局部變量定義在局部范圍內(nèi):如方法,函數(shù),語句中,只在作用域有效
2.局部變量沒有默認(rèn)初始化值
3.局部變量存在于棧內(nèi)存中,作用的范圍結(jié)束,變量空間會自動釋放

3. 靜態(tài)變量:

用static關(guān)鍵字修飾的變量,被所有對象所共享

全局變量(成員變量)與靜態(tài)變量的區(qū)別:

  1. 生命周期不同
  • 全局變量隨對象創(chuàng)建而創(chuàng)建,隨對象銷毀而銷毀
  • 靜態(tài)變量隨類加載而加載,隨類消失而消失
  1. 調(diào)用方式不同
  • 全局變量只能被對象調(diào)用
  • 靜態(tài)變量可以被對象調(diào)用,也可以被類名調(diào)用
  1. 別名不同
  • 全局變量也稱為實例變量。
  • 靜態(tài)變量也稱為類變量。
  1. 數(shù)據(jù)存儲位置不同
  • 全局變量存儲在堆內(nèi)存的對象中,所以也叫對象的特有數(shù)據(jù)。
  • 靜態(tài)變量數(shù)據(jù)存儲在方法區(qū)(共享數(shù)據(jù)區(qū))的靜態(tài)區(qū),所以也叫對象的共享數(shù)據(jù)。

差異對比:

image.png

基本數(shù)據(jù)類型(8個):

int,byte,char,short,float,double,long,boolean

包裝類數(shù)據(jù)(8個):

Integer,Byte,Character,Short,Float,Double,Long,Boolean

java中的數(shù)據(jù)存儲:

  1. 寄存器(register)。 這是最快的存儲區(qū),因為它位于不同于其他存儲區(qū)的地方——處理器內(nèi)部。但是寄存器的數(shù)量極其有限,所以寄存器由編譯器根據(jù)需求進(jìn)行分配。你不能直接控制,也不能在程序中感覺到寄存器存在的任何跡象。

------最快的存儲區(qū), 由編譯器根據(jù)需求進(jìn)行分配,我們在程序中無法控制

  1. 棧(stack)。位于通用RAM中,但通過它的“堆棧指針”可以從處理器哪里獲得支持。堆棧指針若向下移動,則分配新的內(nèi)存;若向上移動,則釋放那些 內(nèi)存。這是一種快速有效的分配存儲方法,僅次于寄存器。創(chuàng)建程序時候,JAVA編譯器必須知道存儲在堆棧內(nèi)所有數(shù)據(jù)的確切大小和生命周期,因為它必須生成 相應(yīng)的代碼,以便上下移動堆棧指針。這一約束限制了程序的靈活性,所以雖然某些JAVA數(shù)據(jù)存儲在堆棧中——特別是對象引用,但是JAVA對象不存儲其 中。

------存放基本類型的變量數(shù)據(jù)和對象,數(shù)組的引用,但對象本身不存放在棧中,而是存放在堆(new 出來的對象)或者常量池中(字符串常量對象存放在常量池中)

  1. 堆(heap)。一種通用性的內(nèi)存池(也存在于RAM中),用于存放所有的JAVA對象。堆不同于堆棧的好處是:編譯器不需要知道要從堆里分配多少存儲區(qū)域,也不必知道存儲的數(shù)據(jù)在堆里存活多長時間。因此,在堆里分配存儲有很大的靈活性。當(dāng)你需要創(chuàng)建一個對象的時候,只需要new寫一行簡單的代碼,當(dāng)執(zhí)行這行代碼時,會自動在堆里進(jìn)行存儲分配。當(dāng)然,為這種靈活性必須要付出相應(yīng)的代價,用堆進(jìn)行存儲分配比用堆棧進(jìn)行存儲存儲需要更多的時間

------存放所有new出來的對象。

  1. 靜態(tài)存儲(static storage)。這里的“靜態(tài)”是指“在固定的位置”。靜態(tài)存儲里存放程序運行時一直存在的數(shù)據(jù)。你可用關(guān)鍵字static來標(biāo)識一個對象的特定元素是靜態(tài)的,但JAVA對象本身從來不會存放在靜態(tài)存儲空間里。

------存放靜態(tài)成員(static定義的)

  1. 常量存儲(constant storage)。常量值通常直接存放在程序代碼內(nèi)部,這樣做是安全的,因為它們永遠(yuǎn)不會被改變。有時,在嵌入式系統(tǒng)中,常量本身會和其他部分分割離開,所以在這種情況下,可以選擇將其放在ROM中

------存放字符串常量和基本類型常量(public static final)

  1. 非RAM存儲。如果數(shù)據(jù)完全存活于程序之外,那么它可以不受程序的任何控制,在程序沒有運行時也可以存在。

------硬盤等永久存儲空間

就速度來說,有如下關(guān)系:

寄存器 > 棧 > 堆 > 其它

這里我們主要關(guān)心棧,堆和常量池,對于棧和常量池中的對象可以共享,對于堆中的對象不可以共享。
棧中的數(shù)據(jù)大小和生命周期是可以確定的,當(dāng)沒有引用指向數(shù)據(jù)時,這個數(shù)據(jù)就會消失。堆中的對象的由垃圾回收器負(fù)責(zé)回收,因此大小和生命周期不需要確定,具有很大的靈活性。

棧內(nèi)存:

某一個函數(shù)被調(diào)用時,這個函數(shù)會在棧內(nèi)存里面申請一片空間,以后在這個函數(shù)內(nèi)部定義的變量,都會分配到這個函數(shù)所申請到的棧。當(dāng)函數(shù)運行結(jié)束時,分配給函數(shù)的??臻g被收回,在這個函數(shù)中被定義的變量也隨之被釋放和消失。棧內(nèi)存比堆內(nèi)存小得多

堆內(nèi)存:

通過new產(chǎn)生的數(shù)組和對象分配在堆內(nèi)存中。堆內(nèi)存中分配的內(nèi)存,由JVM提供的GC(垃圾回收機制)來管理。在堆內(nèi)存中產(chǎn)生了一個數(shù)組對象后,我們還可以在棧中定義一個變量,這個棧中變量的取值等于堆中對象的首地址。棧內(nèi)存中的變量就成了堆內(nèi)存中數(shù)組或者對象的引用變量。我們以后就可以在程序中直接使用棧中的這個變量來訪問我們在堆中分配的數(shù)組或者對象,引用變量相當(dāng)于數(shù)組或者對象起的一個別名,或者代號。

引用變量是一個普通的變量,定義時在棧中分配;引用變量在被運行到它的作用域之外時就被釋放,而我們的數(shù)組和對象本身是在堆中分配的,即使程序運行到使用new產(chǎn)生對象的語句所在的函數(shù)或者代碼之后,我們剛才被產(chǎn)生的數(shù)組和對象也不會被釋放。數(shù)組和對象只是在沒有引用變量指向它,也就是沒有任何引用變量的值等于它的首地址,它才會變成垃圾不會被使用,但是它任然占據(jù)著內(nèi)存空間不放(這也就是我們Java比較吃內(nèi)存的一個原因),在隨后一個不確定的時間被垃圾回收器收走。

堆內(nèi)存和棧內(nèi)存的區(qū)別

1、應(yīng)用程序所有的部分都使用堆內(nèi)存,然后棧內(nèi)存通過一個線程運行來使用。

2、不論對象什么時候創(chuàng)建,他都會存儲在堆內(nèi)存中,棧內(nèi)存包含它的引用。棧內(nèi)存只包含原始值變量和堆中對象變量的引用。

3、存儲在堆中的對象是全局可以被訪問的,然而棧內(nèi)存不能被其他線程所訪問。

4、棧中的內(nèi)存管理使用LIFO的方式完成,而堆內(nèi)存的管理要更復(fù)雜了,因為它是全局被訪問的。堆內(nèi)存被分為,年輕一代,老一代等等(Young Generation and Old Generation.)。

5、棧內(nèi)存是生命周期很短的,然而堆內(nèi)存的生命周期從程序的運行開始到運行結(jié)束。

6、我們可以使用-Xms和-Xmx JVM選項定義開始的大小和堆內(nèi)存的最大值,我們可以使用-Xss定義棧的大小

7、當(dāng)棧內(nèi)存滿的時候,Java拋出java.lang.StackOverFlowError異常而堆內(nèi)存滿的時候拋出java.lang.OutOfMemoryError: Java Heap Space錯誤

8、和堆內(nèi)存比,棧內(nèi)存要小的多,因為明確使用了內(nèi)存分配規(guī)則(LIFO),和堆內(nèi)存相比棧內(nèi)存非常快。

例(引用):
String 類型的變量通常有兩種賦值方式:一種直接賦值,例如String a = "hello world";另一種是用構(gòu)造方法,例如 String b = new String ("hello world");那么這里的a 和b是否相等呢?他們又有什么不同 呢?
如果用=作比較,則它們不相等,因為“=”比較的是基本數(shù)據(jù)類型的值是否相等或者比較對象是否為同一個對象;而變量a和變量b指向的是兩個不同的對象,為什么這么說呢?先來理解一下2個變量的賦值過程,對于表達(dá)式String a = "hello world",會先創(chuàng)建一個字符串對象“hello world”,而這個字符串實際上是放在字符串緩沖區(qū)中,然后把a指向這個對象;而對于String b = new String("hello world");則會創(chuàng)建兩個對象一個是“hello world”這個放在字符串緩沖區(qū)中的,另一個是new 方法構(gòu)造出來的對象new String() 這個對象,新對象中保存的是“hello world”對象罷了,這個對象是放在堆內(nèi)存中,而b 指向這個new String ()對象,這顯然是不同的兩個對象,所以他們用 “=”比較的結(jié)果為false。

如果用equals()方法比較,這結(jié)果為true,因為equals()方法比較的是對象的內(nèi)容,它們的內(nèi)容都為“hello world”。
另外值得提醒的是,字符串緩沖區(qū)中對相同的字符串只會存一次。假如我們同時寫了String a ="hello world";String b = new String("hello world");那么字符串緩沖區(qū)實際只有一個hello world 字符串,在給b賦值時,會先檢查字符串緩沖區(qū)中是否有“hello world”這個字符串,如果有則不創(chuàng)建,直接new String(),然后賦值,因此這種情況下,表達(dá)式String b= new String ("hello world")也只創(chuàng)建了一個對象。
總結(jié):
棧內(nèi)存:局部變量,對象的引用,基本數(shù)據(jù)類型
堆內(nèi)存:全局變量,包裝類,對象;
————————————————
原文鏈接:https://blog.csdn.net/qq_33371372/article/details/81383312

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容