JAVA面向?qū)ο?3_對(duì)象內(nèi)存管理_繼承的意義(上)_第1頁
JAVA面向?qū)ο?3_對(duì)象內(nèi)存管理_繼承的意義(上)_第2頁
JAVA面向?qū)ο?3_對(duì)象內(nèi)存管理_繼承的意義(上)_第3頁
JAVA面向?qū)ο?3_對(duì)象內(nèi)存管理_繼承的意義(上)_第4頁
JAVA面向?qū)ο?3_對(duì)象內(nèi)存管理_繼承的意義(上)_第5頁
已閱讀5頁,還剩7頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、1. 對(duì)象內(nèi)存管理1.1. 對(duì)象內(nèi)存管理1.1.1. 對(duì)象內(nèi)存管理在JAVA中,有java程序、虛擬機(jī)、操作系統(tǒng)三個(gè)層次,其中java程序與虛擬機(jī)交互,而虛擬機(jī)與操作系統(tǒng)交互。編譯好的java字節(jié)碼文件運(yùn)行在JVM中。程序中無論代碼還是數(shù)據(jù),都需要存儲(chǔ)在內(nèi)存中,而java程序所需內(nèi)存均由JVM進(jìn)行管理分配,開發(fā)者只需關(guān)心JVM是如何管理內(nèi)存的,而無需關(guān)注某種操作系統(tǒng)是如何管理內(nèi)存的,這就保證了java程序的平臺(tái)無關(guān)性。JVM會(huì)將申請(qǐng)的內(nèi)存從邏輯上劃分為三個(gè)區(qū)域:堆、棧、方法區(qū)。這三個(gè)區(qū)域分別用于存儲(chǔ)不同的數(shù)據(jù)。1.2. 堆內(nèi)存1.2.1. 對(duì)象存儲(chǔ)在堆中JVM在其內(nèi)存空間開辟了一個(gè)稱為“堆”的

2、存儲(chǔ)空間,這部分空間用于存儲(chǔ)使用new關(guān)鍵字所創(chuàng)建的對(duì)象。請(qǐng)看如下代碼:1. Cell c = new Cell ();其內(nèi)存分布如圖 1所示:圖- 1從圖示1中可以看到右側(cè)的堆內(nèi)存,new Cell()所創(chuàng)建的對(duì)象在堆中分配,同時(shí)成員變量亦在此分配,并賦初始值為零。引用類型變量c在棧內(nèi)存中分配,其中保存的數(shù)據(jù),為對(duì)象在堆內(nèi)存中的地址信息,假設(shè)對(duì)象在堆內(nèi)存的地址為40DF,則c中保存的即是40DF。1.2.2. 成員變量的生命周期當(dāng)聲明好對(duì)象之后,對(duì)該對(duì)象(堆中的Cell)的訪問需要依靠引用變量(棧中的c),那么當(dāng)一個(gè)對(duì)象沒有任何引用時(shí),該對(duì)象被視為廢棄的對(duì)象,屬于被回收的范圍,同時(shí)該對(duì)象中的

3、所有成員變量也隨之被回收??梢赃@樣認(rèn)為,成員變量的生命周期為:從對(duì)象在堆中創(chuàng)建開始到對(duì)象從堆中被回收結(jié)束。請(qǐng)看如下的代碼,演示了對(duì)象不再被引用:1. Cell c = new Cell();2. c = null ;當(dāng)將c賦值為null時(shí),表示c不再指向剛剛分配的對(duì)象空間,此時(shí)成員變量失效。1.2.3. 垃圾回收機(jī)制垃圾回收器(Garbage Collection,GC)是JVM自帶的一個(gè)線程(自動(dòng)運(yùn)行著的程序),用于回收沒有任何引用所指向的對(duì)象。GC線程會(huì)從棧中的引用變量開始跟蹤,從而判定哪些內(nèi)存是正在使用的,若GC無法跟蹤到某一塊堆內(nèi)存,那么GC就認(rèn)為這塊內(nèi)存不再使用了,即為可回收的。但是

4、,java程序員不用擔(dān)心內(nèi)存管理,因?yàn)槔占鲿?huì)自動(dòng)進(jìn)行管理。1.2.4. Java程序的內(nèi)存泄露問題內(nèi)存泄露是指,不再被使用的內(nèi)存沒有被及時(shí)的回收,嚴(yán)重的內(nèi)存泄露會(huì)因過多的內(nèi)存占用而導(dǎo)致程序的崩潰。在程序中應(yīng)該盡量避免不必要的內(nèi)存浪費(fèi)。GC線程判斷對(duì)象是否可以被回收的依據(jù)是該對(duì)象是否有引用來指向,因此,當(dāng)確定該對(duì)象不再使用時(shí),應(yīng)該及時(shí)的將其引用設(shè)置為null,這樣,該對(duì)象即不再被引用,屬于可回收的范圍。1.2.5. System.gc()方法GC的回收對(duì)程序員來說是透明的,并不一定一發(fā)現(xiàn)有無引用的對(duì)象就立即回收。一般情況下,當(dāng)我們需要GC線程即刻回收無用對(duì)象時(shí),可以調(diào)用System.gc(

5、)方法。此方法用于建議JVM馬上調(diào)度GC線程回收資源,但具體的實(shí)現(xiàn)策略取決于不同的JVM系統(tǒng)。1.3. 非堆-棧1.3.1. 棧用于存放方法中的局部變量JVM在其內(nèi)存空間開辟一個(gè)稱為”?!钡拇鎯?chǔ)空間,這部分空間用于存儲(chǔ)程序運(yùn)行時(shí)在方法中聲明的所有的局部變量,例如,在main方法中有如下代碼:1. Cell c = new Cell ( );2. int num = 5;其內(nèi)存分配如圖 2 所示:圖- 2說明:方法中的變量即為局部變量,是在棧內(nèi)存中分配,若變量為值類型,則在棧中存儲(chǔ)的就是該變量的值。若變量為引用類型,則在棧中存儲(chǔ)的是堆中對(duì)象的地址。1.3.2. 局部變量的生命周期一個(gè)運(yùn)行的Jav

6、a程序從開始到結(jié)束會(huì)有多次方法的調(diào)用。JVM會(huì)為每一個(gè)方法的調(diào)用在棧中分配一個(gè)對(duì)應(yīng)的空間,這個(gè)空間稱為該方法的棧幀。一個(gè)棧幀對(duì)應(yīng)一個(gè)正在調(diào)用中的方法,棧幀中存儲(chǔ)了該方法的參數(shù)、局部變量等數(shù)據(jù)。當(dāng)某一個(gè)方法調(diào)用完成后,其對(duì)應(yīng)的棧幀將被清除,局部變量即失效。1.3.3. 成員變量和局部變量成員變量與局部變量的差別如下:局部變量:1) 定義在方法中;2) 沒有默認(rèn)值,必須自行設(shè)定初始值;3) 方法被調(diào)用時(shí),存在棧中,方法調(diào)用結(jié)束時(shí)局部變量從棧中清除;成員變量:1) 定義在類中,方法外;2) 由系統(tǒng)設(shè)定默認(rèn)初始值,可以不顯式初始化;3) 所在類被實(shí)例化后,存在堆中,對(duì)象被回收時(shí),成員變量失效;1.4.

7、 非堆-方法區(qū)1.4.1. 方法區(qū)用于存放類的信息方法區(qū)用于存放類的信息,Java程序運(yùn)行時(shí),首先會(huì)通過類裝載器載入類文件的字節(jié)碼信息,經(jīng)過解析后將其裝入方法區(qū)。類的各種信息(包括方法)都在方法區(qū)存儲(chǔ),看如下代碼:1. Cell c = new Cell();程序在執(zhí)行這句話時(shí),Cell類首先被裝載到JVM的方法區(qū),其中包括類的基本信息和方法定義等,如下圖 3 所示:圖- 3通過圖示可以看出,在方法區(qū)中,包含Cell類的字節(jié)碼文件,及類的基本信息及方法drop等。1.4.2. 方法只有一份當(dāng)類的信息被加載到方法區(qū)時(shí),除了類的類型信息以外,同時(shí)類內(nèi)的方法定義也被加載到方法區(qū);類在實(shí)例化對(duì)象時(shí),多

8、個(gè)對(duì)象會(huì)擁有各自在堆中的空間,但所有實(shí)例對(duì)象是共用在方法區(qū)中的一份方法定義的。意味著,方法只有一份??慈缦麓a:1. JFrame f1 = new JFrame(); 2. JFrame f2 = new JFrame(); 3. f1.setSize(200, 300);4. f2.setSize(300,400); 如上的代碼中,對(duì)象有兩個(gè),但是setSize方法只有一份,分別針對(duì)f1指向的對(duì)象和f2指向的對(duì)象調(diào)用了兩次。2. 繼承的意義(上)2.1. 繼承2.1.1. 泛化的過程前面的案例中定義了T類和J類, 通過分析可以發(fā)現(xiàn), 在這兩個(gè)類中存在著大量的重復(fù)代碼,像cells屬性、pr

9、int方法、drop方法、moveLeft方法、moveRight方法,在這兩個(gè)類中都存在,并且實(shí)現(xiàn)上基本也是相同的,本著代碼重用的原則,可以使用繼承的方式來實(shí)現(xiàn)。首先,構(gòu)建T類和J類的父類Tetromino類,將公共的(T類和J類公有的)信息存放在父類中, T類和J類繼承Tetromino父類。此時(shí),子類即可以共享父類的數(shù)據(jù)。這個(gè)過程就是泛化的過程。2.1.2. extends關(guān)鍵字使用繼承可以實(shí)現(xiàn)代碼的重用,在java語言中,需要通過extends關(guān)鍵字實(shí)現(xiàn)類的繼承。繼承完成后,子類(Sub class)可以繼承父類(Super class)的成員變量及成員方法,同時(shí)子類也可以定義自己的成

10、員變量和成員方法。屆時(shí),子類將具有父類的成員及本類的成員。需要注意的是,Java語言不支持多重繼承,即:一個(gè)類只能繼承一個(gè)父類,但一個(gè)父類可以有多個(gè)子類。看下面的代碼:1. public class Tetromino 2. Cell cells;3. public Tetromino() 4. cells = new Cell4;5. 6. public void drop() /同寫過的T類 7. public void moveLeft() /同寫過的T類8. public void moveRight() /同寫過的T類9. public void print() /同寫過的T類10.

11、 11. public class TetrominoT extends Tetromino 12. public TetrominoT(int row, int col) 13. cells0 = new Cell(row, col);14. cells1 = new Cell(row, col + 1);15. cells2 = new Cell(row, col + 2);16. cells3 = new Cell(row + 1, col + 1); 17. 18. 如上代碼說明:聲明父類Tetromino,將公共信息放在其中,包括Cell聲明、drop()方法、moveLeft()方

12、法、moveRight()方法,print()方法。聲明無參構(gòu)造函數(shù),對(duì)成員變量Cell數(shù)組進(jìn)行實(shí)例化。聲明子類TetrominoT繼承Tetromino,并聲明有參構(gòu)造函數(shù),傳遞行row,列col參數(shù),進(jìn)行T型數(shù)組元素的初始化。下面在main方法中,聲明一個(gè)T型對(duì)象,即可以實(shí)現(xiàn)T型對(duì)象的構(gòu)建:1. TetrominoT t = new TetrominoT( 1 , 1);上面的代碼,在創(chuàng)建子類對(duì)象時(shí),調(diào)用了子類的有參構(gòu)造函數(shù)進(jìn)行數(shù)據(jù)的初始化,試想下,父類Tetromino的無參構(gòu)造函數(shù)執(zhí)行了嗎?通過分析可以肯定的是,父類的無參構(gòu)造函數(shù)被執(zhí)行了。在程序中并沒有聲明父類的構(gòu)造函數(shù),那它是如何執(zhí)

13、行的呢?2.1.3. 繼承中構(gòu)造方法父類的無參構(gòu)造方法之所以被執(zhí)行,是因?yàn)閖ava規(guī)定,子類在構(gòu)造之前必須先構(gòu)造父類。事實(shí)上,子類的構(gòu)造方法中是必須要通過super關(guān)鍵字來調(diào)用父類的構(gòu)造方法的,這樣才可以保證妥善的初始化繼承自父類的成員變量。但是看上一個(gè)案例中的代碼并沒有super調(diào)用父類構(gòu)造方法,那是因?yàn)?,如果子類的?gòu)造方法中沒有調(diào)用父類的構(gòu)造方法,則java編譯器會(huì)自動(dòng)的加入對(duì)父類無參構(gòu)造方法的調(diào)用。請(qǐng)看如下代碼,演示了super關(guān)鍵字的用法:1. public TetrominoT(int row, int col) 2. super ( ) ; 3. cells0 = new Cell

14、(row, col);4. cells1 = new Cell(row, col + 1);5. 6. 上面的代碼中,super();為編譯器自動(dòng)加入的,并且super關(guān)鍵字必須位于子類構(gòu)造方法的第一行,否則會(huì)有編譯錯(cuò)誤。另外一點(diǎn)需要注意的是,若父類沒有提供無參的構(gòu)造方法,則會(huì)出現(xiàn)編譯錯(cuò)誤。請(qǐng)看如下的示例:1. class Foo /父類2. int value;3. Foo(int value) 4. this.value = value;5. 6. 7. class Goo extends Foo /子類8. int num;9. Goo(int num) 10. this.num = n

15、um;11. 12. 分析上面的代碼,在子類構(gòu)造方法中沒有寫super調(diào)用父類構(gòu)造方法,這時(shí)編譯器會(huì)默認(rèn)添加super()來調(diào)用父類的無參構(gòu)造方法,但是父類中又沒有定義無參的構(gòu)造方法,因此會(huì)發(fā)生編譯錯(cuò)誤。針對(duì)上面的問題,可以有兩種解決方案,方案一為在父類中添加無參的構(gòu)造方法,方案二為在子類構(gòu)造方法中顯示調(diào)用父類的有參構(gòu)造方法(常常使用),這樣可以保證父類的成員變量均被初始化,參見下面的代碼:1. class Goo extends Foo 2. int num;3. Goo(int value, int num) 4. super(value);5. this.num = num6. 7. 如

16、上的代碼,在子類中調(diào)用了父類的構(gòu)造方法,初始化了繼承自父類的value成員變量,編譯正確。2.1.4. 父類的引用指向子類的對(duì)象一個(gè)子類的對(duì)象可以向上造型為父類的類型。即,定義父類型的引用可以指向子類的對(duì)象??慈缦麓a所示:1. class Foo 2. int value;3. public void f() 4. Foo(int value) 5. this.value = value;6. 7. 8. class Goo extends Foo 9. int num;10. public void g() 11. Goo(int value, int num) 12. super(val

17、ue);13. this.num = num14. 15. 16. class Test public static void main(String args)17. Foo obj = new Goo(100,3);18. 19. 上面的代碼,在main方法中,聲明了父類型的引用來指向子類型的對(duì)象。但是通過父類的引用只能訪問父類所定義的成員,而不能訪問子類所擴(kuò)展的部分??聪旅娴拇a:1. class Foo 2. int value;3. public void f() 4. 5. 6. class Goo extends Foo 7. int num;8. public void g() 9. 10. 11. class Test12. public static void main(String

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論