<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    The NoteBook of EricKong

      BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
      611 Posts :: 1 Stories :: 190 Comments :: 0 Trackbacks
      1.

     

    有這樣一種說法,如今爭鋒于IT戰(zhàn)場的兩大勢力,MS一族偏重于底層實(shí)現(xiàn),Java一族偏重于系統(tǒng)架構(gòu)。說法根據(jù)無從考證,但從兩大勢力各自的社區(qū)力量和圖書市場已有佳作不難看出,此說法不虛,但掌握J(rèn)ava的底層實(shí)現(xiàn)對Java程序員來說是至關(guān)重要的,本文介紹了Java中的數(shù)據(jù)在內(nèi)存中的存儲。
      
      2 內(nèi)存中的堆(stack)與棧(heap)
      Java程序運(yùn)行時(shí)有6個(gè)地方可以存儲數(shù)據(jù),它們分別是寄存器、棧、堆、靜態(tài)存儲、常量存儲和非RAM存儲,主要是堆與棧的存儲。

     

         【隨機(jī)存儲器 :Random Access Memory 】


      棧與堆都是Java用來在RAM中存放數(shù)據(jù)的地方。與C++不同,Java自動管理?xiàng):投眩绦騿T不能直接地設(shè)置棧或堆。棧的優(yōu)勢是,存取速度比堆要快,僅次于直接位于CPU中的寄存器。另外,棧數(shù)據(jù)可以共享。但缺點(diǎn)是,存在棧中的數(shù)據(jù)大小與生存期必須是確定的,缺乏靈活性。堆的優(yōu)勢是可以動態(tài)地分配內(nèi)存大小,生存期也不必事先告訴編譯器,Java的垃圾收集器會自動收走這些不再使用的數(shù)據(jù)。但缺點(diǎn)是,由于要在運(yùn)行時(shí)動態(tài)分配內(nèi)存,存取速度較慢


      【 寄存器位于CPU中 】


      3 Java中數(shù)據(jù)在內(nèi)存中的存儲
      3.1基本數(shù)據(jù)類型的存儲
      Java的基本數(shù)據(jù)類型共有8種,即int, short, long, byte, float, double, boolean, char(注意,并沒有string的基本類型)。這種類型的定義是通過諸如int a = 3; long b = 255L;的形式來定義的,稱為自動變量。值得注意的是:自動變量存的是字面值,不是類的實(shí)例,即不是類的引用,這里并沒有類的存在如int a = 3;這里的a是一個(gè)指向int類型的引用,指向3這個(gè)字面值。這些字面值的數(shù)據(jù),由于大小可知,生存期可知(這些字面值固定定義在某個(gè)程序塊里面,程序塊退出后,字段值就消失了),出于追求速度的原因,就存在于棧中


      另外,棧有一個(gè)很重要的特殊性,就是存在棧中的數(shù)據(jù)可以共享

        假設(shè)我們同時(shí)定義:
      int a = 3;

        int b=3;
      編譯器先處理int a = 3;首先它會在棧中創(chuàng)建一個(gè)變量為a的引用,然后查找有沒有字面值為3的地址,沒找到,就開辟一個(gè)存放3這個(gè)字面值的地址,然后將a指向3的地址。接著處理int b = 3;在創(chuàng)建完b這個(gè)引用變量后,由于在棧中已經(jīng)有3這個(gè)字面值,便將b直接指向3的地址。這樣,就出現(xiàn)了a與b同時(shí)均指向3的情況。

       【上文提到了"引用+數(shù)值+內(nèi)存地址"這三個(gè)名詞,其中變量名就是引用,給變量賦的值就是數(shù)值,

     

        而所提到的內(nèi)存是抽象的內(nèi)容,讓引用指向的不是數(shù)值,而是存取數(shù)值的那塊內(nèi)存地址】

     

      定義完a與b的值后,再令a = 4;那么,b不會等于4,還是等于3。在編譯器內(nèi)部,遇到時(shí),它就會重新搜索棧中是否有4的字面值,如果沒有,重新開辟地址存放4的值;如果已經(jīng)有了,則直接將a指向這個(gè)地址。因此a值的改變不會影響到b的值。

        【定義變量,給變量賦值,然后在編譯的過程中就可以將其保存在內(nèi)存中了】

     
      3.2對象的內(nèi)存模型
      在Java中,創(chuàng)建一個(gè)對象包括對象的聲明和實(shí)例化兩步,下面用一個(gè)例題來說明對象的內(nèi)存模型。
      假設(shè)有類Rectangle定義如下:

       Rectangle:矩形
      class Rectangle{
      double width,height;
      Rectangle(double w,double h){
      width=w;height=h; }}
      (1)聲明對象時(shí)的內(nèi)存模型
      用Rectangle rect;聲明一個(gè)對象rect時(shí),將在棧內(nèi)存為對象的引用變量rect分配內(nèi)存空間,但Rectangle的值為空,稱rect是一個(gè)空對象。空對象不能使用,因?yàn)樗€沒有引用任何“實(shí)體”。
      (2)對象實(shí)例化時(shí)的內(nèi)存模型
      當(dāng)執(zhí)行rect=new Rectangle(3,5);時(shí),會做兩件事
      在堆內(nèi)存中為類的成員變量width,height分配內(nèi)存,并將其初始化為各數(shù)據(jù)類型的默認(rèn)值;接著進(jìn)行顯式初始化(類定義時(shí)的初始化值);最后調(diào)用構(gòu)造方法,為成員變量賦值。
      返回堆內(nèi)存中對象的引用(相當(dāng)于首地址)給引用變量rect,以后就可以通過rect來引用堆內(nèi)存中的對象了。

        (他奶奶的,不是很理解這兩句話!)


      (3)創(chuàng)建多個(gè)不同的對象實(shí)例
      一個(gè)類通過使用new運(yùn)算符可以創(chuàng)建多個(gè)不同的對象實(shí)例,這些對象實(shí)例將在堆中被分配不同的內(nèi)存空間,改變其中一個(gè)對象的狀態(tài)不會影響其他對象的狀態(tài)。例如:
      Rectangle r1=new Rectangle(3,5);
      Rectangle r2=new Rectangle(4,6);
      此時(shí),將在堆內(nèi)存中分別為兩個(gè)對象的成員變量width、height分配內(nèi)存空間,兩個(gè)對象在堆內(nèi)存中占據(jù)的空間是互不相同的。如果有
      Rectangle r1=new Rectangle(3,5);
      Rectangle r2=r1;
      則在堆內(nèi)存中只創(chuàng)建了一個(gè)對象實(shí)例,在棧內(nèi)存中創(chuàng)建了兩個(gè)對象引用,兩個(gè)對象引用同時(shí)指向一個(gè)對象實(shí)例。
      3.3包裝類數(shù)據(jù)的存儲
      基本型別都有對應(yīng)的包裝類:如int對應(yīng)Integer類,double對應(yīng)Double類等,基本類型的定義都是直接在棧中,如果用包裝類來創(chuàng)建對象,就和普通對象一樣了。例如:int i=0;i直接存儲在棧中。  Integer i(i此時(shí)是對象) = new Integer(5);這樣,i對象數(shù)據(jù)存儲在堆中,i的引用存儲在棧中,通過棧中的引用來操作對象。

        【數(shù)據(jù)存儲在堆中,引用存儲在棧中】


      3.4 String 類型數(shù)據(jù)的存儲
      String是一個(gè)特殊的包裝類數(shù)據(jù)。

    可以用     String str = new String("abc");的形式來創(chuàng)建;

    也可以用   String str = "abc";的形式來創(chuàng)建。

     

    第一種創(chuàng)建方式,和普通對象的的創(chuàng)建過程一樣;

    第二種創(chuàng)建方式,Java內(nèi)部將此語句轉(zhuǎn)化為以下幾個(gè)步驟:
      (1)先定義一個(gè)名為str的對String類的對象引用變量:String str;
      (2)在棧中查找有沒有存放值為“abc”的地址,如果沒有,則開辟一個(gè)存放字面值為“abc”的地址,接著創(chuàng)建一個(gè)新的String類的對象o,并將o的字符串值指向這個(gè)地址,而且在棧中這個(gè)地址旁邊記下這個(gè)引用的對象o。如果已經(jīng)有了值為“abc”的地址,則查找對象o,并返回o的地址。
      (3)將str指向?qū)ο髈的地址


      值得注意的是,一般String類中字符串值都是直接存值的。但像String str = "abc";這種場合下,其字符串值卻是保存了一個(gè)指向存在棧中數(shù)據(jù)的引用。
      為了更好地說明這個(gè)問題,我們可以通過以下的幾個(gè)代碼進(jìn)行驗(yàn)證。
      String str1=“abc”;
      String str2=“abc”;
      System.out.println(s1==s2);//true
      注意,這里并不用str1.equals(str2);的方式,因?yàn)檫@將比較兩個(gè)字符串的值是否相等。==號,根據(jù)JDK的說明,只有在兩個(gè)引用都指向了同一個(gè)對象時(shí)才返回真值。而我們在這里要看的是,str1與str2是否都指向了同一個(gè)對象。
      我們再接著看以下的代碼。
      Stringstr1=new String(“abc”);
      Stringstr2=“abc”;
      System.out.println(str1==str2);//false
      創(chuàng)建了兩個(gè)引用。創(chuàng)建了兩個(gè)對象。兩個(gè)引用分別指向不同的兩個(gè)對象。
      以上兩段代碼說明,只要是用new()來新建對象的,都會在堆中創(chuàng)建,而且其字符串是單獨(dú)存值的,即使與棧中的數(shù)據(jù)相同,也不會與棧中的數(shù)據(jù)共享。
      3.5數(shù)組的內(nèi)存分配
      當(dāng)定義一個(gè)數(shù)組,int x[];或int []x;時(shí),在棧內(nèi)存中創(chuàng)建一個(gè)數(shù)組引用,通過該引用(即數(shù)組名)來引用數(shù)組。x=new int[3];將在堆內(nèi)存中分配3個(gè)保存int型數(shù)據(jù)的空間,堆內(nèi)存的首地址放到棧內(nèi)存中,每個(gè)數(shù)組元素被初始化為0。
      
      4 內(nèi)存空間的釋放
      棧上變量的生存時(shí)間受限于當(dāng)前函數(shù)的生存時(shí)間,函數(shù)退出了,變量就不存在了。在堆中分配的對象實(shí)例,當(dāng)不再有任何一個(gè)引用變量指向它時(shí),這個(gè)對象就可以被垃圾回收機(jī)制回收了。
      
      5 總結(jié)堆棧

      再來看Java的內(nèi)存,棧內(nèi)存用來存放一些基本類型的變量和數(shù)組及對象的引用變量,而堆內(nèi)存主要是來放置對象實(shí)例的。明白這個(gè)就能很好的解釋多態(tài)、繼承、覆蓋方面的問題了

    posted on 2010-06-13 08:48 Eric_jiang 閱讀(2054) 評論(0)  編輯  收藏 所屬分類: Java
    主站蜘蛛池模板: 美女黄频视频大全免费的| 浮力影院亚洲国产第一页| 97视频免费在线| 在线看片免费人成视久网| 国产成人久久AV免费| 在线播放免费人成毛片乱码| 成人免费区一区二区三区 | 亚洲中文字幕无码一区| 亚洲精品高清在线| 亚洲综合久久夜AV | 亚洲精品亚洲人成在线观看| 亚洲AV无码乱码国产麻豆| 亚洲老熟女@TubeumTV| 亚洲国产成人九九综合| 狠狠色香婷婷久久亚洲精品| 亚洲第一成年免费网站| 欧亚一级毛片免费看| 国产特黄特色的大片观看免费视频| 热久久这里是精品6免费观看| 久久久久国产免费| 老司机在线免费视频| 日本不卡视频免费| 亚洲国产一区二区视频网站| 亚洲熟妇中文字幕五十中出| 久久久国产精品亚洲一区| 亚洲综合一区无码精品| 香港经典a毛片免费观看看| 热久久这里是精品6免费观看| 蜜桃AV无码免费看永久| 免费看www视频| 国产亚洲成人在线播放va| 亚洲国产精品不卡在线电影| 久久国产亚洲精品| 日韩成人毛片高清视频免费看| 毛片免费在线观看| A级毛片内射免费视频| 免费人成年激情视频在线观看 | 国产v片免费播放| 亚洲免费观看视频| 亚洲国产情侣一区二区三区| 豆国产96在线|亚洲|