Java中數據數據存儲

注:僅是整理總結,發現錯誤之處望及時告知,感激不盡。今日看到關於常量池、堆的東西,發現心裏一點概念也不記得了,故做次筆記加深印象。

一、Java中數據存放的位置

(缺少硬件部分的關聯)
1、寄存器
——最快的存儲區,處理器內部,由編譯器分配
2、棧
——僅次於寄存器的存儲方法,位於通用RAM中,由堆棧指針的移動決定新增或釋放內存。存放基本類型的變量數據和對象,數組的引用,但對象本身不存放在棧中,而是在堆或常量池中
3、堆
——一種通用性的內存池(RAM中),存放所有Java對象(new出來的),動態分配(即運行時)
4、靜態存儲(static storage)
——存放程序運行時一直存在的數據,static標識的元素
5、常量池
——常量通常直接存放在程序代碼內部,字符串常量和基本類型常量(public static final)
6、非RAM存儲:硬盤等永久存儲空間

二、棧、堆、常量池的區別

速度:寄存器>棧>堆>其他

對於棧和常量池中的對象可以共享,堆中的對象不可共享(共享是什麼層面上的意思??)
棧中的數據大小和生命週期是可以確定的,當沒有引用指向數據時,這個數據就會消失;堆中的對象由垃圾回收器扶着回收
對於字符串:其對象的引用都是存儲在棧中的,如果是編譯器已經創建好(直接用雙引號定義的)的就存儲在常量池中,如果是運行期(new出來的)才能確定的近存儲在堆中。 對於通過 new 產生一個字符串(假設爲 ”china” )時,會先去常量池中查找是否已經有了 ”china” 對象,如果沒有則在常量池中創建一個此字符串對象,然後堆中再創建一個常量池中此 ”china” 對象的拷貝對象。這也就是有道面試題: String s = new String(“xyz”); 產生幾個對象?一個或兩個,如果常量池中原來沒有 ”xyz”, 就是兩個。

 對於基礎類型的變量和常量:變量和引用存儲在棧中,常量存儲在常量池中。
 對於成員變量和局部變量:成員變量就是方法外部,類的內部定義的變量;局部變量就是方法或語句塊內部定義的變量。局部變量必須初始化。形式參數是局部變量,局部變量的數據存在於棧內存中。棧內存中的局部變量隨着方法的消失而消失。成員變量存儲在堆中的對象裏面,由垃圾回收器負責回收。
如以下Java代碼 
class BirthDate { 
    private int day; 
    private int month; 
    private int year;     
    public BirthDate(int d, int m, int y) { 
        day = d;  
        month = m;  
        year = y; 
    } 
    省略get,set方法……… 

 
public class Test{ 
    public static void main(String args[]){ 
        int date = 9; 
        Test test = new Test();       
        test.change(date);  
        BirthDate d1= new BirthDate(7,7,1970);        
    }   
 
    public void change1(int i){ 
        i = 1234; 
    } 
 
    對於以上這段代碼,date爲局部變量,i,d,m,y都是形參爲局部變量,day,month,year爲成員變量。下面分析一下代碼執行時候的變化:
    1. main方法開始執行:int date = 9;
        date局部變量,基礎類型,引用和值都存在棧中。
    2. Test test = new Test();
        test爲對象引用,存在棧中,對象(new Test())存在堆中。
    3. test.change(date);
        i爲局部變量,引用和值存在棧中。當方法change執行完成後,i就會從棧中消失。
    4. BirthDate d1= new BirthDate(7,7,1970); 
        d1 爲對象引用,存在棧中,對象(new BirthDate())存在堆中,其中d,m,y爲局部變量存儲在棧中,且它們的類型爲基礎類型,因此它們的數據也存儲在棧中。 day,month,year爲成員變量,它們存儲在堆中(new BirthDate()裏面)。當BirthDate構造方法執行完之後,d,m,y將從棧中消失。
    5.main方法執行完之後,date變量,test,d1引用將從棧中消失,new Test(),new BirthDate()將等待垃圾回收。

三、具體使用

1、對於基本類型,定義方式諸如int a = 3;char b = 'a';的形式來定義的稱爲自動變量,自動變來個存的是字面值,不是類的實例(即不是類的引用),a是指向int類型的引用,指向3這個字面值。而3這個字面值就存在於棧中。

關於棧中數據共享的解釋:相等的字面值的引用指向棧內同一個字面值。例int x=1;int y=1;首先創建變量x的引用並開闢一個存放字面值1的地址,x指向這塊地址;處理int y=1時,先創建y的引用變量後,發現棧中已有字面值1,直接將y指向1的地址即可。

2、對於包裝類數據,如Integer,String,Double等,這些類數據全部存於堆中,Java用new語句來顯示地告訴編譯器,在運行時纔會跟局需要動態創建。
對於自動拆箱、裝箱需要注意:把int變成Integer的時候,如果int那隻在-128~127之間,返回的並不是新new出來的Integer對象,而是一個已緩存在堆中的Integer對象;
Integer c = 127;   
        Integer d = 127;   
        Integer e = 128;   
        Integer f = 128;  
//編譯器後臺進行Integer f = new Integer(128)的轉換
System.out.println(c==d);   //true  
        System.out.println(e==f);   //false  

3、字符串包裝類數據(String):
3.1 String str = "asd"創建過程:
a.首先在常量池中查找是否有“asd”字符串對象
b1.若有直接讓str引用該對象
b2.若無則在常量池中創建“asd”,並讓str引用該對象
常量池屬於類信息的一部分,而類信息對應存在於JVM內存模型的方法區,而方法區是在JVM內存模型中的堆中有JVM來分配。所以“asd”可以說存在於堆中(不過,爲了把方法區的堆區別於JVM的堆,有些資料會把方法區稱爲棧)。“asd”在編譯時會被寫入字節碼中,當class文件被加載時,JVM就爲“asd”在常量池中分配內存,所以和靜態區差不多(靜態區是什麼
3.2 String str = new String ("asd")的創建過程
a.首先在堆中(不是常量池)創建對象“asd”,並讓str引用指向該對象
b.在字符串常量池中查看是否存在內容爲“asd”的字符串對象
c1.若存在,則將new出來的字符串對象與字符串常量池中的對象聯繫起來(什麼叫聯繫起來
c2.若不存在,則在字符串常量池中創建內容爲“asd”的字符串對象,並將堆中的對象與之聯繫起來

關注intern()方法,返回該字符串在常量池中的對象的引用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章