JAVA面向對象_第1頁
JAVA面向對象_第2頁
JAVA面向對象_第3頁
JAVA面向對象_第4頁
JAVA面向對象_第5頁
已閱讀5頁,還剩58頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

1、Top1. 對象和類(上)1. 對象和類(上)1.1. 面向對象程序設計1.1.1. 面向過程的結構化程序設計首先來看一個需求,實現(xiàn)員工信息管理,將員工簡歷信息中的數(shù)據(jù):姓名、性別、年齡、薪水, 存儲在信息管理系統(tǒng)中進行操作。可以定義一個輸出雇員信息的方法進行數(shù)據(jù)的輸出,傳遞4個參數(shù),代碼如下:1. /* 打印員工信息的方法 */2. public static void printEmpInfo(String name,int age, 3. char gender,double salary) 4. System.out.println("-");5. System.o

2、ut.println("姓名: " + name);6. System.out.println("年齡:" + age);7. System.out.println("性別:" + gender);8. System.out.println("薪水:" + salary);9. 在main() 方法中聲明雇員信息數(shù)據(jù)(分別為4個變量), 然后調用如上的輸出雇員方法進行數(shù)據(jù)的輸出,當提升工資后,再調用輸出方法輸出,代碼如下:1. /* 打印雇員信息 */2. public static void main (Stri

3、ng args )3. /雇員14. String emp1Name = "黃河大蝦"5. int emp1Age = 25;6. char emp1Gender = '男'7. double emp1Salary = 8000.00;8. 9.      /打印員工信息10. printEmpInfo(emp1Name, emp1Age, emp1Gender, emp1Salary);11. 12. /修改員工工資(增長20%)并打印13. emp1Salary *= 120.0 / 100.0;14. print

4、EmpInfo(emp1Name, emp1Age,emp1Gender, emp1Salary);15. 如上代碼的實現(xiàn)方式即為面向過程的結構化程序設計, 何為面向過程?面向過程是一種以過程為核心的編程思想,即分析出解決問題所需要的步驟,然后使用方法將這些步驟一步一步的實現(xiàn),使用的時候,在main方法中一個一個依次調用就可以了。分析如上代碼,看看結構化程序的弊端所在,首先,如上代碼缺乏對數(shù)據(jù)的封裝,變量emp1Name,emp1Age,emp1Gender,emp1Salary為4個完全獨立的變量, 并不是一個整體。其次,數(shù)據(jù)和方法(對數(shù)據(jù)的操作)的分離,在打印雇員信息方法中,傳遞了4個參數(shù)

5、,而這4個參數(shù)與在main方法中所定義的4個變量并無直接關系。這就是面向過程程序設計的弊端,那如何解決?使用面向對象的程序設計。1.1.2. 什么是抽象數(shù)據(jù)類型面向對象的第一步就是抽象數(shù)據(jù)類型,所謂抽象數(shù)據(jù)類型可以理解為:將不同類型的數(shù)據(jù)的集合組成個整體用來描述一種新的事物。像如上程序中,可以將姓名、年齡、性別、工資這4個不同類型的數(shù)據(jù)組成一個整體來描述雇員這個新事物。1.1.3. 什么是類類定義了一種抽象數(shù)據(jù)類型,而類不但定義了抽象數(shù)據(jù)類型的組成(成員變量),同時還定義了對該類型可以實施的操作(方法)??慈缦麓a定義了雇員類:1. /* 定義雇員類 */2. public class Emp

6、3. String name;4. int age;5. char gender;6. double salary;7. 在如上的實例代碼中,僅僅定義了Emp類型的組成,即成員變量。該類定義了4個成員變量:String類型的name用于存放名字;int類型的age用于存放年齡;char類型的gender用于存放性別;double類型的salary用于存放工資。這個時候printEmpInfo()方法的參數(shù)也可以進行修改了, 可以將其改為Emp類型(Emp是一種抽象數(shù)據(jù)類型),這樣可以看出是將一個雇員信息當作了一個整體來操作,看如下代碼:1. public static void printEm

7、pInfo(Emp emp) 2.     System.out.println("-");3.     System.out.println("姓名: " + );4.     System.out.println("年齡:" + emp.age);5.     System.out.println("性別:" + emp.gender);

8、6.     System.out.println("薪水:" + emp.salary);7. 當調用如上方法時,需要傳遞一個Emp類型的數(shù)據(jù),稱之為Emp類型的對象。每個Emp類型的對象都包含name、age、gender和salary四個成員,通過“.”的方式進行訪問。下面看一下在main ()方法中的調用代碼:1. public static void main(String args) 2. Emp emp1 = new Emp(); /使用new關鍵字創(chuàng)建Emp類型的對象3.     

9、; = "黃河大蝦"4.     emp1.age = 25;5.     emp1.gender = '男'6.     emp1.salary = 8000; /為該對象的各個成員變量賦值7.8.     printEmpInfo(emp1);9.     emp1.salary *= 120.0 / 100.0;10.  

10、60;  printEmpInfo(emp1); /使用該對象調用printEmpInfo方法11. 分析如上幾段代碼可以看出,定義了Emp類以后,提升了代碼的模塊化以及代碼的重用性,但程序依然存在問題,即:打印信息的方法是只針對Emp數(shù)據(jù)的操作,屬于Emp自身的方法,需要實現(xiàn)數(shù)據(jù)和方法(對該類數(shù)據(jù)的操作)的統(tǒng)一,也就是說,可以將打印信息的方法也放在Emp中定義,修改后的完整代碼如下所示:1. /*進一步修改后的雇員類*/2. public class Emp3. String name;4. int age;5. char gender;6. double salary;

11、7.8. /*打印信息的方法*/9. public void printInfo() /定義在類中,可直接對成員變量進行操作10. System.out.println("-");11. System.out.println("姓名: " + name);12. System.out.println("年齡:" + age);13. System.out.println("性別:" + gender);14. System.out.println("薪水:" + salary);15. 16.

12、17. /*針對修改后的Emp類的使用方式*/18. public class EmpManager 19. public static void main(String args) 20. Emp emp2 = new Emp();21.          = "白發(fā)饃女"22.         emp2.age = 24;23.      

13、60;  emp2.gender = '女'24.         emp2.salary = 6000;25.         /*調用方法打印信息*/ /創(chuàng)建完Emp對象后,對其成員變量賦值,然后調26.         emp2.printInfo(); /用其printInfo()方法打印各個成員變量信息27. &

14、#160;       emp2.salary *= 125.0 / 100.0;28.         emp2.printInfo();    29. 30. 通過上面的代碼,很好的實現(xiàn)了對數(shù)據(jù)的封裝,并且實現(xiàn)了數(shù)據(jù)與方法的統(tǒng)一。這種方式即為面向對象方式,即:以對象為中心來構建軟件系統(tǒng)。1.2. 定義一個類1.2.1. 定義類的成員變量類是一種引用數(shù)據(jù)類型。類為對象的模板,簡單的說就是分類。類的定義包括

15、“成員變量”的定義和“方法”的定義,其中“成員變量”用于描述一類對象共同的數(shù)據(jù)結構。在Java語言中,類的成員變量的定義可以使用如下語法:1. class 類名 2. 成員變量類型 變量名稱;3. 4. 定義好類之后,可以創(chuàng)建該類的對象,對象創(chuàng)建之后,其成員變量可以按照默認的方式初始化;對象成員變量的默認初始化值規(guī)則如下圖 - 5所示:圖- 51.2.2. 定義類的方法類中除了定義成員變量,還可以定義方法,用于描述對象的形為,封裝對象的功能。在Java語言中,可以按照如下方式定義類中的方法:1. class 類名 2. 返回值類型 方法名稱(參數(shù)列表) 3. 方法體4.   

16、;  5.      6. 下面,通過案例對成員方法進行演示,需求:為方塊類定義drop()方法如下所示:1. class Cell 2.     int row ; int col ;3.     /*方塊下落的方法*/4.     public void drop ( ) 5.         row +;  &#

17、160;  /行+,即下落6.     7. 調用方法,也和訪問成員變量一樣,通過“.”符號,代碼如下:1. /* 創(chuàng)建方塊類對象,調用下落方法,并打印效果*/2. class TestCell 3. public static void main(String args)4. System.out.println("-繪制Cell-");5.      Cell cell = new Cell();6.      cell.row = 15;7

18、.      cell.col = 6;8.      printCell(cell);9.  10.      System.out.println("-Cell下落一行-");11.      /調用drop方法,下落一行12.      cell.drop();13.      printCell(cell); 14. 1

19、5. 1.3. 創(chuàng)建并使用對象1.3.1. 使用new關鍵字創(chuàng)建對象類定義完成后,可以使用new關鍵字來創(chuàng)建對象。new運算的語法為: new 類名();此創(chuàng)建對象的過程也通常稱為實例化。javax.swing.JFrame是JDK提供的一個類,用于封裝顯示在桌面上的一個窗體。使用new JFrame()可以創(chuàng)建一個窗體對象,如下圖 1所示:圖- 11.3.2. 引用類型變量為了能夠對實例化的對象進行訪問控制,需一個特殊的變量,即引用。對引用有兩點需要說明:1. 引用類型變量可以存儲該類對象的地址信息,通常稱為“指向該類的對象”,當一個引用類型變量指向該類的對象,就可以通過這個變量對對象實施訪

20、問。2. 除8種基本類型之外,用類、接口、數(shù)組等聲明的變量都稱為引用類型變量,簡稱“引用”。可以看圖 3,描述了類、對象、引用之間的關系:圖- 3當創(chuàng)建了引用類型變量之后,就可以通過引用來訪問對象的成員變量或調用方法,如下代碼所示:1. Emp emp = new Emp();2. =“黃河大俠”; /訪問對象的成員變量3.4. JFrame frame = new JFrame();5. frame.setSize(200,300); /調用方法. 訪問對象的成員變量、調用方法當創(chuàng)建了引用后,即可以通過引用來訪問對象的成員變量,以及調用方法??慈缦碌氖纠?.

21、Cell c = new Cell();2. c.row = 2;3. c.col = 3; /訪問成員變量4. c.drop();5. c.moveLeft(2);6. String str = c.getCellInfo(); /調用方法1.3.4. 引用類型變量的賦值引用類型變量存儲的是對象的地址信息, 對引用類型變量的賦值, 除了使用上面的new關鍵字以外,還可以有另外一種賦值方式, 即:相同類型的引用類型變量之間相互賦值。 需要注意的是:引用類型變量之間的賦值不會創(chuàng)建新的對象,但有可能會使兩個以上的引用指向同一個對象。 請看如下代碼:1. Emp e1 = new Emp();2.

22、Emp e2 = e1; /將e1的值(對象的地址信息)賦給e2,e2和e1指向相同的對象。 3. =“黃河大蝦”;4. = “白發(fā)饃女”;5. System.out.println(); 如上代碼的輸出結果為:白發(fā)饃女。因為e1與e2存儲的地址相同,也就意味著e1與e2指向了同一個對象,那么對該對象的修改,將會影響所有對該對象的引用。1.3.5. null和NullPointerException對于引用類型變量,除了上面的兩種賦值方式之外,還可以對其賦值為null。null的含義為“空”,表示還沒有指向任何對象。例如:1. Emp emp =

23、null; /引用emp中的值為null,沒有指向任何對象; 2. emp = new Emp(); /引用emp指向了一個Emp對象; 需要注意:當一個引用的值為null的時候,如果通過引用訪問對象成員變量或者調用方法是不合邏輯的(因其沒有指向某對象,自然不會有屬性和方法)。此時,會產(chǎn)生NullPointerException(空指針異常)。異常的詳細概念后面詳細講。請看下面的代碼,將就產(chǎn)生NullPointerException:1. JFrame frame = null;2. frame.setSize(200,300);Top1. 對象和類(下)2. 數(shù)組1. 對象和類(下)1.1.

24、 方法的重載1.1.1. 方法的簽名方法的簽名包含如下兩個方面:方法名和參數(shù)列表。Java語法規(guī)定,一個類中不可以有兩個方法簽名完全相同的方法,即:一個類中不可以有兩個方法的方法名和參數(shù)列表都完全相同,但是,如果一個類的兩個方法只是方法名相同而參數(shù)列表不同,是可以的。下面看如下代碼:1. public class Cashier 2. public boolean pay(double money) 3. public boolean pay(double money) 4. 分析如上代碼,結論會出現(xiàn)編譯錯誤,因為在同一個類Cashier中的兩個方法,簽名相同,這在java語法中是不允許出現(xiàn)的

25、。而下面的代碼就是正確的:1. public class Cashier 2. public boolean pay(double money) 3. public boolean pay(String cardId,4. String cardPwd) 5. 可以看到上面的代碼,在類Cashier中,雖然pay方法名相同,但是參數(shù)列表不同,這樣是被允許的,可以正常編譯通過。1.1.2. 方法重載及其意義假想收款窗口的設計,可以采用兩種方式:1. 開設三個窗口,分別用來接收現(xiàn)金,信用卡和支票的交付方式(分別在窗口上標明),用戶根據(jù)需要選擇窗口,并投入指定的物件,如圖 8所示:圖- 81. 開設

26、一個窗口,標為“收款”,可以接收現(xiàn)金,信用卡和支票三種物件。該窗口可以按照輸入的不同物件實施不同的操作。例如,如果輸入的是現(xiàn)金則按現(xiàn)金支付,如果輸入的是信用卡則按信用卡支付,以此類推,如圖 9所示。圖- 9通過對如上兩種方式的分析,請問:哪種方式更好一些呢?常規(guī)情況下認為,相對于A的方式,B的設計可以降低用戶的負擔,用戶去付款時不需要去找對應的窗口,只需要到收款窗口就可以了, 減少了用戶使用時的錯誤,B的設計更加優(yōu)雅一些。按B的設計方式即為方法重載,在Java語言中,允許多個方法的名稱相同,但參數(shù)列表不同,此種方式稱為方法的重載(overload)。下面的代碼即為收款窗口的兩種設計方式,可以看

27、出B方式即為方法的重載方式。1. public class PayMoney /-A方式2. payByCash(double money) 3. payByCard(String cardId,StringcardPwd) 4. payByCheck(String compayName,double money) 5. 6. public class PayMoney /-B方式7. pay(double money) 8. pay(String cardId,StringcardPwd) 9. pay(String compayName,double money) 10. 通過如上的代碼可

28、以看出,按照A的方式若想付款,需在三個方法之中進行選擇,不同的方法即為不同的付款方式,而B的方式即為重載方式,若想付款,只需要找到pay方法,只不過,傳遞不同的參數(shù)即可。1.1.3. 編譯時根據(jù)簽名綁定調用方法當調用重載的方法時,編譯器會在編譯時根據(jù)簽名的不同來綁定調用不同的方法,可以把重載的方法看成是完全不同的方法,只不過,恰好方法名稱相同而已。請看下面的兩組代碼:重載方法:1. pay(double money) 2. pay(String cardId,StringcardPwd) 3. pay(String compayName,double money) 調用方法:(只管調用即可,由

29、編譯器來根據(jù)簽名綁定不同的方法)1. pay(8888.88);2. pay(“12345678”,”666666”);    3. pay( “tarena”, 8888.88);1.2. 構造方法1.2.1. 構造方法語法結構構造方法是在類中定義的方法, 但不同于其他的方法,構造方法的定義有如下兩點規(guī)則:1. 構造方法的名稱必須與類名相同。2. 構造方法沒有返回值,但也不能寫void。如下所示為構造方法的語法:1. 【訪問修飾符】類名( ) 2. /構造方法體3. 1.2.2. 通過構造方法初始化成員變量Java語言中的構造方法常常用于實現(xiàn)對對象成員

30、變量的初始化,如下代碼展示了構造方法的使用。1. class Cell 2. int row ;3. int col ; 4. public Cell (int row1 , int col1)5.         row = row1; 6. col = col1;7. 8. 9. class TestCell 10. public static void main(String args )11. Cell c1 = new Cell( 15 , 6 );12.     

31、 printCell(c1);13. 14. 可以看出,在創(chuàng)建對象時,構造方法寫在new關鍵字之后,可以理解為:“new”創(chuàng)建了對象,而構造方法對該對象進行了初始化。1.2.3. this關鍵字的使用在上面的代碼中,為該構造方法定義了兩個參數(shù),分別表示行和列。為了區(qū)分于Cell類的成員變量row和col,為兩個參數(shù)分別取名為row1和col1,這顯然不是一種好方法,因為,我們會希望依然使用變量row來表示行,col來表示列,而不是row1和col1。為了解決這個問題,需要使用到this關鍵字。this關鍵字用在方法體中,用于指代調用該方法的當前對象,簡單的說:哪個對象調用方法,this指的就是

32、哪個對象。嚴格來講,在方法中需要通過this關鍵字指明當前對象。請看如下代碼:1. public void drop ( ) 2. this.row +;    3. 上面的drop()方法可以解釋為:將調用該方法對象的成員變量的row加1。很多時候,為了方便起見,在沒有歧義的情況下可以省略this,如下所示:1. public void drop ( ) 2. row +;    3. 在構造方法中,用來初始化成員變量的參數(shù)一般和成員變量取相同的名字,這樣會有利于代碼的可讀性,但此處就必須通過this關鍵字來區(qū)分

33、成員變量和參數(shù)了,而不能省略this了,如下代碼所示:1. public Cell (int row , int col ) 2.     this . row = row ;3.     this . col = col ;4. 如上的代碼中,this.row表示的為Cell類的成員變量,而row為參數(shù)變量。1.2.4. 默認的構造方法JAVA語法規(guī)定,任何一個類都必須含有構造方法,假如源程序中沒有定義,則編譯器在編譯時將為其添加一個無參的空構造方法(此方法稱之為“默認的構造方法”)。例如:先前所定義的Cell類

34、源文件中沒有寫構造方法,但也可以編譯成功,因為在編譯時由編譯器為其添加了如下的構造方法:1. Cell( ) 但是有一個問題需要注意,當類定義了構造方法后,Java編譯器將不再添加默認的構造方法,看如下代碼:1. class Cell2.     int row; 3. int col;4.     Cell (int row,int col)5.         this.row = row;6.    

35、     this.col = col;7.     8. 9. public class CellGame 10. public static void main(String args) 11. Cell cell = new Cell( ); /編譯錯誤12. 13. 可以看出,在創(chuàng)建Cell類對象時,發(fā)生了一個編譯期錯誤,那是因為,在Cell類中已經(jīng)定義了Cell(int,int)的構造方法,此時,編譯器將不會再提供無參的構造方法了。所以此處發(fā)生了編譯期錯誤。1.2.5. 構造方法的重載很多時候,

36、為了使用的方便,可以對一個類定義多個構造方法,這些構造方法都有相同的名稱(類名),只是方法的參數(shù)不同,稱之為構造方法的重載。在創(chuàng)建對象時,Java編譯器會根據(jù)不同的參數(shù)調用來不同構造方法。看如下的幾組構造方法的聲明及調用。1. 聲明:2. Cell ( int row , int col ) 3. 4. 調用:5. Cell c1 = new Cell ( 5 , 6 );6.7. 聲明:8. Cell ( ) 9. 10. 調用:11. Cell c1 = new Cell ( ) ;12.13. 聲明:14. Cell (int row) 15. this(row , row );16.

37、17. 調用:18. Cell c1 = new Cell ( 5 ) ;可以注意到,在第三段聲明的構造方法中,使用了this關鍵字,在構造方法中可以通過this關鍵字來調用另外的一個重載的構造方法。this(row,row)調用了第一段聲明Cell(int row, int col)構造方法。2. 數(shù)組2.1. 引用類型數(shù)組2.1.1. 數(shù)組是對象在java中,數(shù)組屬于引用數(shù)據(jù)類型,數(shù)組對象存放在堆中存儲,數(shù)組變量屬于引用類型,存儲數(shù)組對象的地址信息,指向數(shù)組對象。而數(shù)組的元素可以看成數(shù)組對象的成員變量(只不過類型全部相同)??慈缦麓a:1. int arr = new int 3 內(nèi)存的分

38、配如下圖 4所示:圖- 4說明: 在堆內(nèi)存中分配了數(shù)組對象,分配三個int型空間,并將每個元素賦初始值為0,棧中存儲對堆中數(shù)據(jù)的引用,即堆中int數(shù)組的首地址。2.1.2. 引用類型數(shù)組的聲明剛剛聲明的數(shù)組為基本類型數(shù)組,除了基本類型數(shù)組以外,也可以聲明引用類型數(shù)組。所謂引用類型數(shù)組,即數(shù)組元素的類型不是基本類型(int,char,float。) , 而是引用類型,看如下代碼:1. Cell cells = new Cell 4 ;其內(nèi)存分配如下圖 5所示:圖- 5從上圖示可以看出,new Cell4實際是分配了4個空間用于存放4個Cell類型的引用,并賦初始值為null,而并非是分配了4個C

39、ell類型的對象。2.1.3. 引用類型數(shù)組的初始化前面所介紹的基本類型數(shù)組的默認值同成員變量默認的初始值(如int類型的數(shù)組初始值為0),而引用類型數(shù)組的默認初始值都是null。如果希望每一個元素都指向具體的對象,則需要針對每一個數(shù)組元素進行“new”運算。與基本類型數(shù)組一樣,也可以采用靜態(tài)初始化的方式進行初始化操作。如下代碼所示:1. Cell cells = new Cell4;2. cells0 = new Cell(0,4);3. cells1 = new Cell(1,3);4. cells2 = new Cell(1,4);5. cells3 = new Cell(1,5);等價

40、于:1. Cell cells = new Cell 2.     new Cell(0,4) ,3.     new Cell(1,3) ,4.     new Cell(1,4) , 5.     new Cell(1,5) 6. ;如上數(shù)組內(nèi)存分配圖如下圖 6 所示:圖- 62.1.4. 數(shù)組的類型是基本類型數(shù)組前面所介紹的數(shù)組的元素或為基本類型int,或為引用類型Cell,而數(shù)組本身也是一種數(shù)據(jù)類型,當然也可以作為數(shù)組的元素???/p>

41、下面的代碼:1. int arr = new int3 ;2. arr0 = new int2;3. arr1 = new int3;4. arr2 = new int2;5. arr11 = 100;分析如上代碼可以看出,變量arr指向一個數(shù)組,該數(shù)組有三個元素,每個元素都是int類型數(shù)組,長度分別為2,3,2,arr11=100表示將arr數(shù)組中的第2個元素(數(shù)組)的第2個元素賦值為100, 其內(nèi)存分配如圖 7所示:圖- 7對于元素為數(shù)組的數(shù)組,如果每個數(shù)組元素的長度相同,也可以采用如下的方式聲明:1. int row = 3, col = 4;2. int arr = new intro

42、wcol;3. for (int i = 0; i < row; i+) 4. for (int j = 0; j < col; j+) 5. arrij = i * j;6. 7. 如上形式的數(shù)組可以用來表示類似“矩陣”這樣的數(shù)據(jù)結構(3行4列),如下圖-8所示,arrij 可以認為訪問行號為i,列號為j的那個元素。在其他的一些語言中有專門表示這樣結構的所謂二維數(shù)組;但嚴格的講,Java語言中沒有真正的二維數(shù)組。圖- 8Top1. 對象內(nèi)存管理2. 繼承的意義(上)1. 對象內(nèi)存管理1.1. 對象內(nèi)存管理1.1.1. 對象內(nèi)存管理在JAVA中,有java程序、虛擬機、操作系統(tǒng)三個

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

44、);其內(nèi)存分布如圖 1所示:圖- 1從圖示1中可以看到右側的堆內(nèi)存,new Cell()所創(chuàng)建的對象在堆中分配,同時成員變量亦在此分配,并賦初始值為零。引用類型變量c在棧內(nèi)存中分配,其中保存的數(shù)據(jù),為對象在堆內(nèi)存中的地址信息,假設對象在堆內(nèi)存的地址為40DF,則c中保存的即是40DF。1.2.2. 成員變量的生命周期當聲明好對象之后,對該對象(堆中的Cell)的訪問需要依靠引用變量(棧中的c),那么當一個對象沒有任何引用時,該對象被視為廢棄的對象,屬于被回收的范圍,同時該對象中的所有成員變量也隨之被回收。可以這樣認為,成員變量的生命周期為:從對象在堆中創(chuàng)建開始到對象從堆中被回收結束。請看如下的

45、代碼,演示了對象不再被引用:1. Cell c = new Cell();2. c = null ;當將c賦值為null時,表示c不再指向剛剛分配的對象空間,此時成員變量失效。1.2.3. 垃圾回收機制垃圾回收器(Garbage Collection,GC)是JVM自帶的一個線程(自動運行著的程序),用于回收沒有任何引用所指向的對象。GC線程會從棧中的引用變量開始跟蹤,從而判定哪些內(nèi)存是正在使用的,若GC無法跟蹤到某一塊堆內(nèi)存,那么GC就認為這塊內(nèi)存不再使用了,即為可回收的。但是,java程序員不用擔心內(nèi)存管理,因為垃圾收集器會自動進行管理。1.2.4. Java程序的內(nèi)存泄露問題內(nèi)存泄露是指

46、,不再被使用的內(nèi)存沒有被及時的回收,嚴重的內(nèi)存泄露會因過多的內(nèi)存占用而導致程序的崩潰。在程序中應該盡量避免不必要的內(nèi)存浪費。GC線程判斷對象是否可以被回收的依據(jù)是該對象是否有引用來指向,因此,當確定該對象不再使用時,應該及時的將其引用設置為null,這樣,該對象即不再被引用,屬于可回收的范圍。1.2.5. System.gc()方法GC的回收對程序員來說是透明的,并不一定一發(fā)現(xiàn)有無引用的對象就立即回收。一般情況下,當我們需要GC線程即刻回收無用對象時,可以調用System.gc()方法。此方法用于建議JVM馬上調度GC線程回收資源,但具體的實現(xiàn)策略取決于不同的JVM系統(tǒng)。1.3. 非堆-棧1.

47、3.1. 棧用于存放方法中的局部變量JVM在其內(nèi)存空間開辟一個稱為”?!钡拇鎯臻g,這部分空間用于存儲程序運行時在方法中聲明的所有的局部變量,例如,在main方法中有如下代碼:1. Cell c = new Cell ( );2. int num = 5;其內(nèi)存分配如圖 2 所示:圖- 2說明:方法中的變量即為局部變量,是在棧內(nèi)存中分配,若變量為值類型,則在棧中存儲的就是該變量的值。若變量為引用類型,則在棧中存儲的是堆中對象的地址。1.3.2. 局部變量的生命周期一個運行的Java程序從開始到結束會有多次方法的調用。JVM會為每一個方法的調用在棧中分配一個對應的空間,這個空間稱為該方法的棧幀。

48、一個棧幀對應一個正在調用中的方法,棧幀中存儲了該方法的參數(shù)、局部變量等數(shù)據(jù)。當某一個方法調用完成后,其對應的棧幀將被清除,局部變量即失效。1.3.3. 成員變量和局部變量成員變量與局部變量的差別如下:局部變量:1) 定義在方法中;2) 沒有默認值,必須自行設定初始值;3) 方法被調用時,存在棧中,方法調用結束時局部變量從棧中清除;成員變量:1) 定義在類中,方法外;2) 由系統(tǒng)設定默認初始值,可以不顯式初始化;3) 所在類被實例化后,存在堆中,對象被回收時,成員變量失效;1.4. 非堆-方法區(qū)1.4.1. 方法區(qū)用于存放類的信息方法區(qū)用于存放類的信息,Java程序運行時,首先會通過類裝載器載入

49、類文件的字節(jié)碼信息,經(jīng)過解析后將其裝入方法區(qū)。類的各種信息(包括方法)都在方法區(qū)存儲,看如下代碼:1. Cell c = new Cell();程序在執(zhí)行這句話時,Cell類首先被裝載到JVM的方法區(qū),其中包括類的基本信息和方法定義等,如下圖 3 所示:圖- 3通過圖示可以看出,在方法區(qū)中,包含Cell類的字節(jié)碼文件,及類的基本信息及方法drop等。1.4.2. 方法只有一份當類的信息被加載到方法區(qū)時,除了類的類型信息以外,同時類內(nèi)的方法定義也被加載到方法區(qū);類在實例化對象時,多個對象會擁有各自在堆中的空間,但所有實例對象是共用在方法區(qū)中的一份方法定義的。意味著,方法只有一份。看如下代碼:1.

50、 JFrame f1 = new JFrame(); 2. JFrame f2 = new JFrame(); 3. f1.setSize(200, 300);4. f2.setSize(300,400); 如上的代碼中,對象有兩個,但是setSize方法只有一份,分別針對f1指向的對象和f2指向的對象調用了兩次。2. 繼承的意義(上)2.1. 繼承2.1.1. 泛化的過程前面的案例中定義了T類和J類, 通過分析可以發(fā)現(xiàn), 在這兩個類中存在著大量的重復代碼,像cells屬性、print方法、drop方法、moveLeft方法、moveRight方法,在這兩個類中都存在,并且實現(xiàn)上基本也是相同的

51、,本著代碼重用的原則,可以使用繼承的方式來實現(xiàn)。首先,構建T類和J類的父類Tetromino類,將公共的(T類和J類公有的)信息存放在父類中, T類和J類繼承Tetromino父類。此時,子類即可以共享父類的數(shù)據(jù)。這個過程就是泛化的過程。2.1.2. extends關鍵字使用繼承可以實現(xiàn)代碼的重用,在java語言中,需要通過extends關鍵字實現(xiàn)類的繼承。繼承完成后,子類(Sub class)可以繼承父類(Super class)的成員變量及成員方法,同時子類也可以定義自己的成員變量和成員方法。屆時,子類將具有父類的成員及本類的成員。需要注意的是,Java語言不支持多重繼承,即:一個類只能繼

52、承一個父類,但一個父類可以有多個子類??聪旅娴拇a:1. public class Tetromino 2.     Cell cells;3.     public Tetromino() 4.         cells = new Cell4;5.     6.     public void drop() /同寫過的T類 7.   

53、;  public void moveLeft() /同寫過的T類8.     public void moveRight() /同寫過的T類9.     public void print() /同寫過的T類10. 11. public class TetrominoT extends Tetromino 12.     public TetrominoT(int row, int col) 13.     

54、60;   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

55、+ 1); 17.     18. 如上代碼說明:聲明父類Tetromino,將公共信息放在其中,包括Cell聲明、drop()方法、moveLeft()方法、moveRight()方法,print()方法。聲明無參構造函數(shù),對成員變量Cell數(shù)組進行實例化。聲明子類TetrominoT繼承Tetromino,并聲明有參構造函數(shù),傳遞行row,列col參數(shù),進行T型數(shù)組元素的初始化。下面在main方法中,聲明一個T型對象,即可以實現(xiàn)T型對象的構建:1. TetrominoT t = new TetrominoT( 1 , 1);上面的代碼,在創(chuàng)建子類對象

56、時,調用了子類的有參構造函數(shù)進行數(shù)據(jù)的初始化,試想下,父類Tetromino的無參構造函數(shù)執(zhí)行了嗎?通過分析可以肯定的是,父類的無參構造函數(shù)被執(zhí)行了。在程序中并沒有聲明父類的構造函數(shù),那它是如何執(zhí)行的呢?2.1.3. 繼承中構造方法父類的無參構造方法之所以被執(zhí)行,是因為java規(guī)定,子類在構造之前必須先構造父類。事實上,子類的構造方法中是必須要通過super關鍵字來調用父類的構造方法的,這樣才可以保證妥善的初始化繼承自父類的成員變量。但是看上一個案例中的代碼并沒有super調用父類構造方法,那是因為,如果子類的構造方法中沒有調用父類的構造方法,則java編譯器會自動的加入對父類無參構造方法的調

57、用。請看如下代碼,演示了super關鍵字的用法:1. public TetrominoT(int row, int col) 2. super ( ) ; 3.     cells0 = new Cell(row, col);4.     cells1 = new Cell(row, col + 1);5.         6. 上面的代碼中,super();為編譯器自動加入的,并且super關鍵字必須位于子類構造方法的第一行,否則會有

58、編譯錯誤。另外一點需要注意的是,若父類沒有提供無參的構造方法,則會出現(xiàn)編譯錯誤。請看如下的示例: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 = num;11. 12. 分析上面的代碼,在子類構造方法中沒有寫super調用父類構造方法,這時編譯器會默認添加super()來調用父類的無參構造方法,但是父類中又沒有定義無參的構造方法,因此會發(fā)生編譯錯誤。針對上面

59、的問題,可以有兩種解決方案,方案一為在父類中添加無參的構造方法,方案二為在子類構造方法中顯示調用父類的有參構造方法(常常使用),這樣可以保證父類的成員變量均被初始化,參見下面的代碼:1. class Goo extends Foo 2. int num;3. Goo(int value, int num) 4. super(value);5. this.num = num6. 7. 如上的代碼,在子類中調用了父類的構造方法,初始化了繼承自父類的value成員變量,編譯正確。2.1.4. 父類的引用指向子類的對象一個子類的對象可以向上造型為父類的類型。即,定義父類型的引用可以指向子類的對象。看如下代碼所示: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. in

溫馨提示

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

評論

0/150

提交評論