《Java程序案例教程》課件第5章_第1頁
《Java程序案例教程》課件第5章_第2頁
《Java程序案例教程》課件第5章_第3頁
《Java程序案例教程》課件第5章_第4頁
《Java程序案例教程》課件第5章_第5頁
已閱讀5頁,還剩156頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第5章類的基本形式5.1面向?qū)ο蟪绦蛟O(shè)計的基本概念

5.2類與對象

5.3類的封裝性

5.4在類內(nèi)部調(diào)用方法

5.5引用數(shù)據(jù)類型的傳遞5.6匿名對象5.7構(gòu)造方法5.8對象的比較5.9this關(guān)鍵字的使用5.10static關(guān)鍵字的使用5.11構(gòu)造方法的私有5.12對象數(shù)組的使用

5.1面向?qū)ο蟪绦蛟O(shè)計的基本概念

早期的程序設(shè)計經(jīng)歷了“面向問題”、“面向過程”的階段,隨著計算機技術(shù)的發(fā)展,以及所要解決問題的復(fù)雜性的提高,以往的程序設(shè)計方法已經(jīng)不能適應(yīng)這種發(fā)展的需求,于是從20世紀70年代開始,相繼出現(xiàn)了多種面向?qū)ο蟮某绦蛟O(shè)計語言(如圖5-1所示),并逐漸產(chǎn)生了面向?qū)ο蟮某绦蛟O(shè)計方法。面向?qū)ο蟮某绦蛟O(shè)計涉及對象、封裝、類、繼承及多態(tài)等基本概念。圖5-1計算機語言的發(fā)展過程5.1.1對象

何謂面向?qū)ο竽??面向?qū)ο蟪绦蛟O(shè)計是將人們認識世界過程中普遍采用的思維方法應(yīng)用到程序設(shè)計中。對象是現(xiàn)實世界中存在的事物,它們是有形的,如某個人、某種物品,也可以是無形的,如某項計劃、某次商業(yè)交易。對象是構(gòu)成現(xiàn)實世界的一個獨立單位,人們對世界的認識,是從分析對象的特征入手的。

對象的特征分為靜態(tài)特征和動態(tài)特征兩種。靜態(tài)特征指對象的外觀、性質(zhì)、屬性等;動態(tài)特征指對象具有的功能、行為等??陀^事物是錯綜復(fù)雜的,但人們總是從某一目的出發(fā),運用抽象分析的能力,從眾多特征中抽取最具代表性、最能反映對象本質(zhì)的若干特征加以詳細研究。人們將對象的靜態(tài)特征抽象為屬性,用數(shù)據(jù)來描述,在Java語言中稱之為變量;人們將對象的動態(tài)特征抽象為行為,用一組代碼來表示,完成對數(shù)據(jù)的操作,在Java語言中稱之為方法。一個對象由一組屬性和一組對屬性進行操作的方法構(gòu)成。

5.1.2類

具有相同屬性及相同行為的一組對象稱為類。廣義地講,具有共同性質(zhì)的事物的集合稱為類。在面向?qū)ο蟪绦蛟O(shè)計中,類是一個獨立的單位,它有一個類名,其內(nèi)部包括成員變量,用于描述對象的屬性,還包括類的成員方法,用于描述對象的行為。在Java程序設(shè)計中,類被認為是一種抽象數(shù)據(jù)類型,這種數(shù)據(jù)類型不但包括數(shù)據(jù),還包括方法。這大大擴充了數(shù)據(jù)類型的概念。

類是一個抽象的概念,要利用類的方式來解決問題,必須用類創(chuàng)建一個實例化的類對象,然后通過類對象去訪問類的成員變量,去調(diào)用類的成員方法來實現(xiàn)程序的功能。這類同于“汽車”本身是一個抽象的概念,只有使用了一輛具體的汽車,才能感受到汽車的功能。一個類可創(chuàng)建多個類對象,它們具有相同的屬性模式,但可以具有不同的屬性值。Java程序為每一個類對象都開辟了內(nèi)存空間,以便保存各自的屬性值。

面向?qū)ο蟮某绦蛟O(shè)計具有如下三個主要特征:

(1)封裝性;

(2)繼承性;

(3)多態(tài)性。5.1.3封裝性

封裝是面向?qū)ο蟮姆椒ㄋ鶓?yīng)遵循的一個重要原則。它有兩個含義:一是指把對象的屬性和行為看成一個密不可分的整體,將這兩者“封裝”在一個不可分割的獨立單位(即對象)中;另一層含義指“信息隱蔽”,把不需要讓外界知道的信息隱藏起來。有些對象的屬性及行為允許外界用戶知道或使用,但不允許更改,而另一些屬性或行為則不允許外界知曉,或只允許使用對象的功能,而盡可能隱蔽對象的功能實現(xiàn)細節(jié)。封裝機制在程序設(shè)計中表現(xiàn)為,把描述對象屬性的變量及實現(xiàn)對象功能的方法合在一起,定義為一個程序單位,并保證外界不能任意更改其內(nèi)部的屬性值,也不能任意調(diào)動其內(nèi)部的方法。封裝機制的另一個特點是:為封裝在一個整體內(nèi)的變量及方法規(guī)定了不同級別的“可見性”或訪問權(quán)限。

5.1.4繼承性

繼承是面向?qū)ο蠓椒ㄖ械闹匾拍?,并且是提高軟件開發(fā)效率的重要手段。首先擁有反映事物一般特性的類,然后在其基礎(chǔ)上派生出反映特殊事物的類。例如,已有汽車的類,該類中描述了汽車的普遍屬性和行為,進一步再產(chǎn)生轎車的類,轎車的類繼承于汽車類,轎車類不但擁有汽車類的全部屬性和行為,還增加了轎車特有的屬性和行為。在Java程序設(shè)計中,已有的類可以是Java開發(fā)環(huán)境所提供的一批最基本的程序—類庫。用戶開發(fā)的程序類繼承這些已有的類。這樣現(xiàn)在類所描述過的屬性及行為,即已定義的變量和方法,在繼承產(chǎn)生的類中完全可以使用。被繼承的類稱為父類或超類,而經(jīng)繼承產(chǎn)生的類稱為子類或派生類。根據(jù)繼承機制,派生類繼承了超類的所有成員,并相應(yīng)地增加了自己的一些新的成員。面向?qū)ο蟪绦蛟O(shè)計中的繼承機制大大增強了程序代碼的可復(fù)用性,提高了軟件的開發(fā)效率,降低了程序產(chǎn)生錯誤的可能性,也為程序的修改擴充提供了便利。若一個子類只允許繼承一個父類,稱為單繼承;若允許繼承多個父類,稱為多繼承。目前許多面向?qū)ο蟪绦蛟O(shè)計語言不支持多繼承。Java語言通過接口(interface)的方式來彌補由于Java不支持多繼承而帶來的子類不能享用多個父類成員的缺憾。5.1.5類的多態(tài)性

多態(tài)是面向?qū)ο蟪绦蛟O(shè)計的又一個重要特征。多態(tài)是指允許程序中出現(xiàn)重名現(xiàn)象。Java語言中含有方法重載與成員覆蓋兩種形式的多態(tài)。方法重載是指在一個類中,允許多個方法使用同一個名字,但方法的參數(shù)不同,完成的功能也不同。成員覆蓋是指子類與父類允許具有相同的變量名稱,但數(shù)據(jù)類型不同,允許具有相同的方法名稱,但完成的功能不同。

多態(tài)的特性使程序的抽象程度和簡捷程度更高,有助于程序設(shè)計人員對程序的分組進行協(xié)同開發(fā)。 5.2類與對象

面向?qū)ο蟮木幊趟枷肓D使在計算機語言中對事物的描述與現(xiàn)實世界中該事物的本來面目盡可能地一致,類(class)和對象(object)就是面向?qū)ο蠓椒ǖ暮诵母拍睢?/p>

類是對某一類事物的描述,是抽象的、概念上的定義;對象是實際存在的該類事物的個體,因而也稱實例(Instance)。圖5-2就是一個說明類與對象的典型范例。

圖5-2中,汽車設(shè)計圖就是“類”,由這個圖紙設(shè)計出來的若干汽車就是按照該類產(chǎn)生的“對象”。圖5-2類與對象的實例化說明5.2.1類的聲明

在使用類之前,必須先定義它,然后才可利用所定義的類來聲明變量,并創(chuàng)建對象。類定義的語法如下:程序說明:

(1)用class聲明了一個名為Person的類,這里Person是類的名稱。

(2)第3、4行聲明了兩個屬性name和age,name為String型(字符串類型),age為int型(整型)。

(3)第5~8行聲明了一個talk()方法,此方法用于向屏幕打印信息。

為了更好地說明類的關(guān)系,請參見圖5-3。圖5-3Person類圖5.2.2創(chuàng)建新的對象

在實際中單單有類是不夠的,類提供的只是一個模板,必須依照它創(chuàng)建出對象之后才可以使用。下面定義了由類產(chǎn)生對象的基本形式:

類名對象名=new類名();

創(chuàng)建屬于某類的對象,需要通過下面兩個步驟來實現(xiàn):

(1)聲明指向“由類所創(chuàng)建的對象”的變量。

(2)利用new創(chuàng)建新的對象,并指派給先前所創(chuàng)建的變量。

如果要創(chuàng)建Person類的對象,可用下列的語句來實現(xiàn):

Personp; //先聲明一個Person類的對象p

p=newPerson(); //用new關(guān)鍵字實例化Person類的對象p

當(dāng)然也可以用下面這種形式來聲明變量:

Personp=newPerson(); //聲明Person對象p并直接實例化此對象

對象只有在實例化之后才能被使用,而實例化對象的關(guān)鍵字就是new。對象實例化過程如圖5-4所示。圖5-4Person類對象的實例化過程由圖5-4可以看出,當(dāng)語句執(zhí)行到Personp時,只是在棧內(nèi)存中聲明了一個Person的對象p,但是這時p并沒有在堆內(nèi)存中開辟空間,所以這時的p是一個未實例化的對象,用new關(guān)鍵字實際上就是開辟堆內(nèi)存,把堆內(nèi)存的引用賦給了p,這時的p才稱為實例化對象。

如果要訪問對象中的某個成員變量或方法,可以通過下面語法來實現(xiàn):

訪問屬性:對象名稱.屬性名。

訪問方法:對象名稱.方法名()。輸出結(jié)果:

我是:張三,今年:25歲

程序說明:

(1)第6行聲明了一個Person類的實例對象p,并直接實例化此對象。

(2)第7、8行給p對象中的屬性賦值。

(3)第9行調(diào)用talk()方法,在屏幕上輸出信息。

參照上述程序代碼與圖5-5的內(nèi)容即可了解到Java是如何對對象成員進行訪問操作的。圖5-5對Person對象p的訪問操作過程5.2.3創(chuàng)建多個新對象

在例5-3的程序中,只建立了一個Person的對象p,如果需要創(chuàng)建多個對象,則可以依照由類產(chǎn)生對象的基本形式產(chǎn)生多個對象。

【例5-4】

TestPersonDemo1.java。程序說明:

(1)第1~9行聲明了一個新的類Person,類中有name、age兩個屬性,還有一個talk()方法用于輸出信息。

(2)第14~15行聲明了Person的兩個實例對象p1、p2。

(3)第17、18行給p1對象的屬性賦值。

(4)第20、21行給p2對象的屬性賦值。

(5)第23、24行分別用p1、p2調(diào)用Person類中的talk()方法,用于在屏幕上打印信息。

上述程序首先聲明了兩個對象p1和p2,之后分別為p1與p2賦值??梢园l(fā)現(xiàn),p1與p2賦的值互不影響,此關(guān)系可由圖5-6表示出來。圖5-6Person中p1與p2的內(nèi)存分配圖案例1對象組合案例

【案例描述】

編寫一個Circle類,該類的對象可以計算圓的面積。

【代碼與注釋】

程序名稱為Circle.java。

程序代碼如下: 5.3類?的?封?裝?性

【例5-5】

TestPersonDemo2.java。輸出結(jié)果:

我是:張三,今年:-25歲

程序說明:

(1)第1~9行聲明了一個新的類Person,類中有name、age兩個屬性,還有一個talk()方法用于輸出信息。

(2)第15行聲明并實例化Person的對象p。

(3)第17~21行分別為p對象中的屬性賦值,并調(diào)用talk()方法。

由上面的程序可以看出,在程序的第19行將年齡(age)賦值為-25,這明顯是一個不合法的數(shù)據(jù),最終程序在調(diào)用talk()方法時才會打印出這種錯誤的信息。程序說明:

(1)第1~9行聲明了一個新的類Person,類中有name、age兩個屬性,還有一個talk()方法用于輸出信息。與前面不同的是,這里的屬性在聲明時前面都加上了private關(guān)鍵字。

(2)第15行聲明并實例化Person類的對象p。

(3)第17~21行分別為p對象中的屬性賦值,并調(diào)用talk()方法。

可以看出,本程序與例5-5除了在聲明屬性上有些區(qū)別外,并沒有其他區(qū)別,而就是這一個小小的關(guān)鍵字,導(dǎo)致程序連編譯都無法通過,所提示的錯誤為:屬性(name、age)為私有的,所以不能由對象直接進行訪問。程序說明:

(1)第9~25行加入了一些setXxx()、getXxx()方法,主要用來設(shè)置和取得類中的私有屬性。

(2)第13~17行設(shè)置年齡時在程序中加了判斷語句,如果傳入的數(shù)值大于0,則將值賦給age屬性。

(3)第35行調(diào)用了Person類中的setName()方法,并賦值為“張三”。

(4)第37行調(diào)用了setAge()方法,同時傳進了一個-25的不合理年齡。

可以發(fā)現(xiàn)在本程序中,傳進了一個-25的不合理數(shù)值,這樣在設(shè)置Person中的屬性時因為不滿足條件而不能被設(shè)置成功,所以age的值依然為自己的默認值0。這樣在輸出時可以發(fā)現(xiàn),那些錯誤的數(shù)據(jù)并沒有被賦到屬性上,而只輸出了默認值。用private聲明的屬性或方法只能在其類的內(nèi)部被調(diào)用,而不能在類的外部被調(diào)用。讀者可以先暫時簡單理解為:在類的外部不能用對象去調(diào)用private聲明的屬性或方法。下面程序修改自例5-7,在這里將talk()方法封裝了起來。

【例5-8】

TestPersonDemo4.java。程序說明:

(1)第5行將talk()方法用private來聲明。

(2)第9~25行加入了一些setXxx()、getXxx()方法,主要用來設(shè)置和取得類中的私有屬性。

(3)第13~17行設(shè)置年齡時在程序中加了判斷語句,如果傳入的數(shù)值大于0,則將值賦給age屬性。

(4)第35行調(diào)用了類Person中的setName()方法,并賦值為“張三”。

(5)第37行調(diào)用了setAge()方法,同時傳進了一個不合理的年齡-25。 5.4在類內(nèi)部調(diào)用方法

在一個Java程序中是可以通過對象去調(diào)用類中的方法的,當(dāng)然類的內(nèi)部也能互相調(diào)用各自的方法。例如,下面的程序修改自以前的程序代碼,新增加了一個公有的say()方法,并用這個方法去調(diào)用私有的talk()方法。

【例5-9】

TestPersonDemo5.java。輸出結(jié)果:

我是:張三,今年:30歲

程序說明:

(1)第9~12行聲明公有方法say(),此方法用于調(diào)用類內(nèi)部的私有方法talk()。

(2)第42行調(diào)用Person類中的say()方法,其實也就是調(diào)用Person類中的talk()方法。 5.5引用數(shù)據(jù)類型的傳遞

Java中使用引用來取代C++?中的指針,那么什么是引用呢?Java又是怎樣通過引用來取代C++?中的指針的呢?

【例5-10】

TestRefDemo1.java。

程序說明:

(1)第1~5行聲明Person類,有name與age兩個屬性。

(2)第11、13行分別聲明兩個Person的對象p1和p2,但這兩個對象在聲明時都同時賦值為null,表示此對象未實例化。

(3)第15行對對象p1進行實例化。

(4)第17、18行分別為p1對象中的屬性賦值。

(5)第20行將p1的引用賦給p2,此時相當(dāng)于p1與p2都同時指向同一塊堆內(nèi)存。

(6)第22、23行分別調(diào)用和p2.age,輸出p2對象中的屬性。

(7)第24行把p1對象賦值為null,表示此對象不再引用任何內(nèi)存空間。

程序執(zhí)行到第24行時,實際上p1斷開了對其之前實例化對象的引用,而p2則繼續(xù)指向p1原先的引用。

由上述程序可以看出,在程序中并未用new關(guān)鍵字為對象p2實例化,到最后依然可以用與p2.age方式輸出屬性的內(nèi)容,且內(nèi)容與p1對象中的內(nèi)容相似。也就是說,在上述程序中p2是通過p1對象實例化的,或者說p1將其自身的引用傳遞給了p2,如圖5-7所示。圖5-7引用數(shù)據(jù)類型的傳遞如果在程序最后又加了一段代碼,令p2=null,則之前由p1創(chuàng)建的實例化對象不再有任何對象使用它,此對象稱為垃圾對象,如圖5-8所示。圖5-8垃圾對象的產(chǎn)生所謂垃圾對象,就是指程序中不再使用的對象引用。

【例5-11】TestRefDemo2.java。程序說明:

(1)第1~4行聲明一個名為Change的類,其有一個屬性x。

(2)第9行實例化了一個Change類的對象c。

(3)第10行將對象c中的x屬性賦值為20。

(4)第11行調(diào)用fun()方法將對象c傳遞到方法中。

(5)第14~17行聲明fun方法,接收參數(shù)類型為Change類型。

(6)第16行將對象c1中的x屬性賦值為25。

程序最后的輸出結(jié)果為“x=25”,而程序只有在fun()方法中才將x的值賦為25,為什么方法完成之后值依然被保留了下來呢?讀者可以發(fā)現(xiàn)在程序第14行,fun()方法接收的參數(shù)是Changec1,也就是說fun()方法接收的是一個對象的引用。所以在fun方法中所做的操作會影響原先的參數(shù)??梢詤⒖紙D5-9來了解整個過程。圖5-9操作過程

5.6匿名對象

顧名思義,匿名對象就是沒有明確聲明的對象。讀者也可以簡單地理解為只使用一次的對象,即沒有任何一個具體的對象名稱引用它。

【例5-12】TestNoName.java。程序說明:

(1)第1~9行聲明了Person類,其有name與age兩個私有屬性,并分別賦了初值。

(2)第14行聲明了Person匿名對象,調(diào)用Person類中的talk()方法。

從程序中可以看出,用newPerson()聲明的對象并沒有賦給任何一個Person類對象的引用,所以此對象只使用了一次,之后就會被Java的垃圾收集器回收。

5.7構(gòu)造方法

1.構(gòu)造方法的定義

在Java程序中,構(gòu)造方法所完成的主要工作是幫助新創(chuàng)建的對象賦初值。構(gòu)造方法可視為一種特殊的方法,它的定義方式與普通方法類似,其語法如下:在使用構(gòu)造方法時應(yīng)注意以下幾點:

(1)它具有與類名相同的名稱。

(2)它沒有返回值。

構(gòu)造方法沒有返回值,其名稱必須與類的名稱相同,它的調(diào)用時機與一般方法不同。一般方法是在需要時才調(diào)用,而構(gòu)造方法則是在創(chuàng)建對象時便自動調(diào)用,并執(zhí)行構(gòu)造方法的內(nèi)容。因此,構(gòu)造方法無需在程序中直接調(diào)用,而是在對象產(chǎn)生時自動執(zhí)行。

基于上述構(gòu)造方法的特性,可利用它來對對象的數(shù)據(jù)成員進行初始化賦值。所謂初始化,就是為對象賦初值。

下面的程序說明了構(gòu)造方法的使用。

【例5-13】TestConstruct.java。從上述程序中讀者不難發(fā)現(xiàn),在類中聲明的構(gòu)造方法會在實例化對象時自動調(diào)用。讀者可能會問,在之前的程序中用同樣的方法來產(chǎn)生對象,但是在類中并沒有聲明任何構(gòu)造方法,而程序不也一樣正常運行了嗎?實際上,讀者在執(zhí)行javac編譯Java程序時,如果在程序中沒有明確聲明構(gòu)造方法,則系統(tǒng)會自動為類加入一個無參的且什么都不做的構(gòu)造方法,類似于下面代碼:

publicPerson(){}

所以,之前的程序雖然沒有明確聲明構(gòu)造方法,也是可以正常運行的。

2.構(gòu)造方法的重載

在Java中,不僅普通方法可以重載,構(gòu)造方法也可以重載。只要構(gòu)造方法的參數(shù)個數(shù)不同,或是類型不同,便可定義多個名稱相同的構(gòu)造方法。這種做法在Java中是常見的。

【例5-14】TestConstruct1.java。

(3)第20行調(diào)用Person類中含有兩個參數(shù)的構(gòu)造方法(newPerson("張三",25)),同時將姓名和年齡傳到類中,分別為各個屬性賦值。

(4)第21行調(diào)用Person類中的talk()方法,并打印信息。

從上述程序可以看出,構(gòu)造方法的基本作用就是為類中的屬性初始化,在程序產(chǎn)生類的實例對象時,將需要的參數(shù)由構(gòu)造方法傳入,之后再由構(gòu)造方法為其內(nèi)部的屬性進行初始化。這是在一般開發(fā)中經(jīng)常使用的技巧,但是這里有一個問題是讀者應(yīng)該注意的,請看下面的程序。

【例5-15】TestConstruct2.java。可以看出,在編譯程序第20行(Personp=newPerson())時發(fā)生了錯誤,這個錯誤說找不到Person類的無參構(gòu)造方法。前面曾經(jīng)提過,如果程序中沒有聲明構(gòu)造方法,程序就會自動聲明一個無參的且什么都不做的構(gòu)造方法,可是現(xiàn)在卻發(fā)生了找不到無參構(gòu)造方法的問題,這是為什么呢?讀者可以發(fā)現(xiàn)第5~10行已經(jīng)聲明了一個含有兩個參數(shù)的構(gòu)造方法。在Java程序中只要明確聲明了構(gòu)造方法,則默認的構(gòu)造方法將不會被自動生成。要解決這一問題,只需要簡單修改一下Person類即可,可以在Person類中明確地聲明一無參的且什么都不做的構(gòu)造方法。

【例5-16】TestConstruct2.java。 5.8對?象?的?比?較

對象間的比較有兩種方式,即“==”運算符與equals()方法?!?=”操作符用于比較兩個對象的內(nèi)存地址值是否相等,equals()方法用于比較兩個對象的內(nèi)容是否一致。

【例5-17】TestEquals.java。由程序的輸出結(jié)果可以看出,str1不等于str2。有些讀者可能會問,str1與str2的內(nèi)容完全一樣,為什么會不等于呢?程序第5行和第6行分別實例化了String類的兩個對象,此時這兩個對象指向不同的內(nèi)存空間,所以它們的內(nèi)存地址是不一樣的。這時程序中用的是“==”比較,比較的是內(nèi)存地址值,所以輸出str1!=str2。程序第7行將str2的引用賦給str3,這時就相當(dāng)于str3也指向了str2的引用,這兩個對象指向的是同一內(nèi)存地址,所以比較值的結(jié)果是str2==str3。

那么該如何去比較其中的內(nèi)容呢?這就需要采用另外一種方式—equals()方法。

【例5-18】TestEquals1.java。輸出結(jié)果:

str1equalsstr2

str2equalsstr3

可以看出,在程序中將比較方式換成了equals(),而且調(diào)用equals()方法的是String類的對象,所以可知equals()是String類中的方法。特別注意:“==”用于比較內(nèi)存地址值,“equals()”用于比較內(nèi)容。

下面兩種String對象的聲明方式到底有什么不同?

Stringstr1=newString("java");

Stringstr2="java";

下面先來看一個例子。

【例5-19】StringDemo.java。圖5-10String對象的聲明與使用由圖5-10中可以看出,“java”這個字符串在內(nèi)存中開辟一個空間,而str1與str3又同時指向同一內(nèi)存空間,所以即使str1與str3是分兩次聲明的,但最終都指向了同一內(nèi)存空間。str2用new關(guān)鍵字來開辟空間,所以單獨占有自己的一個內(nèi)存空間。

另外,要注意的是,String對象的內(nèi)容一旦聲明,就不能輕易改變。如果要改變一個String對象的值,第一步要做的是將原有的String引用斷開,之后再開辟新的內(nèi)存空間,而且如果用new關(guān)鍵字開辟String對象的內(nèi)存空間,則實際上就開辟了兩個內(nèi)存空間,如圖5-11所示。圖5-11String對象內(nèi)容的改變 5.9this關(guān)鍵字的使用

1.this的本質(zhì)

在整個Java的面向?qū)ο蟪绦蛟O(shè)計中,this是一個比較難理解的關(guān)鍵字,它表示當(dāng)前對象,而所謂的當(dāng)前對象,就是指調(diào)用類中方法或?qū)傩缘哪莻€對象。

【例5-20】Person.java。

Person-1.java這段代碼與Person.java的不同之處在于在第7、8行分別加上了this關(guān)鍵字。此時的和this.age就分別代表類中的name與age屬性,這時再完成賦值操作,就可以清楚地知道誰賦值給誰。完整的程序代碼如下例所示。

【例5-22】TestJavaThis.java。程序說明:

(1)第1~14行聲明了一個名為Person的類。

(2)第5~9行聲明Person類的一個構(gòu)造方法。此構(gòu)造方法的作用是為類中的屬性賦初值。為了更好地說明this是表示當(dāng)前對象的,下面再舉一個例子:判斷兩個對象是否相等,在這里假設(shè)只要姓名、年齡都相同就為同一個人,否則不是同一個人。程序說明:

(1)第1~21行聲明了一個名為Person的類,其中有一個構(gòu)造方法與一個比較方法。

(2)第10~20行在Person類中聲明了一個compare方法,此方法接收Person實例對象的引用。

(3)第12行比較姓名和年齡是否同時相等。

(4)第28行由p1調(diào)用compare方法,將p2傳入到compare方法之中,所以在程序中第12行的就代表,this.age就代表p1.age,而傳入的參數(shù)p2則被compare方法中的參數(shù)p表示。

由此不難理解,this表示當(dāng)前對象這一重要概念,所以程序最后輸出了“相等,是同一人!”的正確判斷信息。

2.用this調(diào)用構(gòu)造方法

如果要在程序中用某一構(gòu)造方法調(diào)用另一構(gòu)造方法,可以用this來實現(xiàn),具體的調(diào)用形式如下:

this();

【例5-24】TestJavaThis1.java。程序說明:

(1)第1~17行聲明一個名為Person的類,類中聲明了一個無參和一個有參兩個構(gòu)造方法。

(2)第12行使用this調(diào)用本類中的無參構(gòu)造方法。

(3)第22行聲明一個Person類的匿名對象,調(diào)用了有參的構(gòu)造方法。

從上述程序可以看出,在第22行雖然調(diào)用了Person中有兩個參數(shù)的構(gòu)造方法,但是由于第12行使用了this調(diào)用本類中的無參構(gòu)造方法,所以程序先去執(zhí)行Person中的無參構(gòu)造方法,之后再去繼續(xù)執(zhí)行其他構(gòu)造方法。如果把this調(diào)用無參構(gòu)造方法的位置任意調(diào)換,則可以在任何時候調(diào)用構(gòu)造方法嗎?實際上這樣理解是錯誤的。構(gòu)造方法是在實例化一對象時被自動調(diào)用的,也就是說在類中的所有方法中只有構(gòu)造方法是被優(yōu)先調(diào)用的,所以使用this調(diào)用構(gòu)造方法必須也只能放在構(gòu)造方法的第一行。下面的程序就是一個錯誤的程序。 5.10static關(guān)鍵字的使用

5.10.1靜態(tài)變量

在程序中如果用static聲明變量,則此變量稱為靜態(tài)變量。那么什么是靜態(tài)變量呢?使用靜態(tài)變量又有什么好處呢?

【例5-25】TestStaticDemo1.java。輸出結(jié)果:

我是:張三,今年:25歲,來自:中國

我是:李四,今年:30歲,來自:中國

我是:王五,今年:35歲,來自:中國

程序說明:

(1)第1~16行聲明一個名為Person的類,含有三個屬性:name、age、city。

(2)第6~11行聲明Person類的一個構(gòu)造方法,此構(gòu)造方法分別為各屬性賦值。

(3)第12~15行聲明一個talk()方法,此方法用于返回用戶信息。

(4)第21~23行分別實例化三個Person對象。

(5)第24~26行分別調(diào)用類中的talk()方法輸出用戶信息。

由上面的程序可以發(fā)現(xiàn),所有的Person對象都有一個city屬性,而且所有的屬性也全部相同,如圖5-12所示。圖5-12static變量內(nèi)存示意圖讀者可以試著想一想,現(xiàn)在假設(shè)程序產(chǎn)生了50個Person對象,如果想修改所有人的city屬性,那么是否就要調(diào)用50遍city屬性進行重新修改呢?顯然這樣太麻煩了。在Java中提供了static關(guān)鍵字,用它來修飾類的屬性后,則此屬性就是公共屬性。將TestStaticDemo1.java程序稍作修改就形成了TestStaticDemo2.java,如下所示。

【例5-26】TestStaticDemo2.java。程序說明:

(1)第1~15行聲明一個名為Person的類,含有三個屬性:name、age、city。其中,city為static類型

(2)第6~10行聲明Person類的一個構(gòu)造方法,此構(gòu)造方法的作用是分別為name、age屬性賦值。

(3)第11~14行聲明一個talk()方法,此方法用于返回用戶信息。

(4)第20~22行分別實例化三個Person對象。

(5)第23~25行分別調(diào)用類中的talk()方法,輸出用戶信息。

(6)第28行修改了p1中的city屬性。從上面的程序中可以發(fā)現(xiàn),程序只在第28行修改了city屬性,而且只修改了一個對象的city屬性,但再次輸出時,發(fā)現(xiàn)全部對象的city值都發(fā)生了一樣的變化,這就說明了用static聲明的屬性是所有對象共享的,如圖5-13所示。圖5-13static變量的使用從圖5-13中可以看出,所有的對象都指向同一個city屬性,只要其中有一個對象修改了city屬性的內(nèi)容,則所有對象都會被同時修改。

另外,需要注意一點,用static方式聲明的屬性也可以用類名直接訪問。例如,要想修改city屬性中的內(nèi)容,則可以用如下方式:

Person.city="美國";

所以有些書上也把用static類型聲明的變量稱為“類變量”。既然static類型聲明的變量是所有對象共享的內(nèi)存空間,也就是說無論最終有多少個對象產(chǎn)生,也都只有一個static類型的屬性,那么可不可以用它來計算類到底產(chǎn)生了多少個實例對象呢?讀者可以想一想,只要一個類產(chǎn)生一個新的實例對象,就都會去調(diào)用構(gòu)造方法,所以可以在構(gòu)造方法中加入一些計數(shù)操作,如下面的程序:5.10.2靜態(tài)方法

static既可以在聲明變量時使用,也可以用其來聲明方法。用它聲明的方法有時被稱為“類方法”。

【例5-27】TestStaticDemo4.java。程序說明:

(1)第1~19行聲明一個名為Person的類,類中含有一個static類型的變量city,并對此對象進行了封裝。

(2)第15~18行聲明一個static類型的方法,此方法也可以用類名直接調(diào)用,用于修改city屬性的內(nèi)容。

(3)第32行由Person調(diào)用setCity()方法,對city的內(nèi)容進行修改。

在使用static類型聲明方法時需要注意的是,如果在類中聲明了一個static類型的屬性,則此屬性既可以在非static類型的方法中使用,也可以在static類型的方法中使用。但用static類型的屬性調(diào)用非static類型的屬性時,會出現(xiàn)錯誤。

【例5-28】PersonStatic.java。5.10.3main()方法

在前面的章節(jié)中已經(jīng)介紹,如果一個類要被Java解釋器直接裝載運行,那么這個類中必須有main()方法。

由于Java虛擬機需要調(diào)用類的main()方法,所以該方法的訪問權(quán)限必須是public,又因為Java虛擬機在執(zhí)行main()方法時不必創(chuàng)建對象,所以該方法必須是static的。該方法接收一個String類型的數(shù)組參數(shù),該數(shù)組中保存執(zhí)行Java命令時傳遞給所運行的類的參數(shù)。

向Java中傳遞參數(shù)可用如下命令:

java類名稱參數(shù)1參數(shù)2參數(shù)3

通過運行下面的程序可了解如何向類中傳遞參數(shù)以及程序又是如何取得這些參數(shù)的。

【例5-29】TestMain.java。運行程序:

javaTestMainfirstsecond

輸出結(jié)果:

first

second

程序說明:

(1)程序第14行判斷輸入?yún)?shù)的個數(shù)是否為兩個參數(shù),如果不是,則退出程序。

(2)所有接收的參數(shù)都被存放在args[]字符串?dāng)?shù)組中,用for循環(huán)輸出全部內(nèi)容。5.10.4靜態(tài)代碼塊

一個類可以使用不包含在任何方法體中的靜態(tài)代碼塊,當(dāng)類被載入時,靜態(tài)代碼塊被執(zhí)行,且只執(zhí)行一次。靜態(tài)代碼塊經(jīng)常用來進行類屬性的初始化。

【例5-30】TestStaticDemo5.java。程序說明:

(1)第1~12行聲明一個名為Person的類。

(2)第8~11行聲明一個靜態(tài)代碼塊,此代碼塊放在Person類中。

(3)第15~18行在類TestStaticDemo5中也聲明一靜態(tài)代碼塊。

(4)第22、23行分別產(chǎn)生了兩個Person類的匿名對象。

從程序運行結(jié)果中可以看出,放在TestStaticDemo5類中的靜態(tài)代碼塊首先被調(diào)用,這是因為程序首先執(zhí)行TestStaticDemo5類,所以此程序的靜態(tài)代碼塊會首先被執(zhí)行。程序在22、23行產(chǎn)生了兩個匿名對象,Person類中的靜態(tài)代碼塊只執(zhí)行了一次,而且靜態(tài)代碼塊優(yōu)先于靜態(tài)方法,由此可以發(fā)現(xiàn),靜態(tài)代碼塊可以為靜態(tài)屬性初始化。案例2static成員變量和實例變量的區(qū)別

【案例描述】

用程序模擬趙莊和李莊兩個村莊,這兩個村莊共用一口水井。

【代碼與注釋】 5.11構(gòu)造方法的私有

方法依實際需要,可分為public與private。同樣地,構(gòu)造方法也有public與private之分。到目前為止,所使用的構(gòu)造方法均屬于public,它可以在程序的任何

溫馨提示

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

評論

0/150

提交評論