版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第3章類與對(duì)象3.1面向?qū)ο缶幊谈拍畹慕榻B3.2類聲明和類體3.3構(gòu)造方法與對(duì)象的創(chuàng)建和使用3.4域/成員變量3.5成員方法3.6this關(guān)鍵字3.7訪問(wèn)權(quán)限3.8嵌套類和內(nèi)部類3.9包
3.1面向?qū)ο缶幊谈拍畹慕榻B
使用面向過(guò)程的編程語(yǔ)言,如C和Fortran,需要選擇數(shù)據(jù)結(jié)構(gòu)和設(shè)計(jì)算法,再把算法翻譯成代碼。而Java是一種面向?qū)ο蟮木幊陶Z(yǔ)言,它不僅具有面向過(guò)程編程語(yǔ)言的特點(diǎn),而且通過(guò)抽象、封裝、繼承和多態(tài)增加了靈活性、模塊性、清晰性和可重用性等極其有用的特性。面向?qū)ο缶幊痰暮诵乃枷刖褪菍?shù)據(jù)和對(duì)數(shù)據(jù)的操作封裝在一起,放入稱之為對(duì)象的實(shí)體中。什么是對(duì)象?在現(xiàn)實(shí)生活中,我們每時(shí)每刻都在與具體的對(duì)象打交道,比如我們身邊的老師、同學(xué)、電腦、手機(jī)等都是對(duì)象。
現(xiàn)實(shí)生活中的對(duì)象都有兩種特征:他們的狀態(tài)和他們的行為。比如同一個(gè)班上的同學(xué)可以由他們的狀態(tài)(姓名,學(xué)號(hào),性別,年齡)和他們的行為(學(xué)習(xí),運(yùn)動(dòng),休息,交談)刻畫;我們常用的電腦也可以由它的狀態(tài)(機(jī)箱,顯示器,主板,CPU,內(nèi)存)和它的行為(開機(jī),關(guān)機(jī),休眠,重啟)刻畫。知道了一個(gè)對(duì)象的狀態(tài)和行為,就能夠從一堆對(duì)象的集合中唯一的揀選出那個(gè)對(duì)象。抽象出現(xiàn)實(shí)生活中對(duì)象的狀態(tài)和行為,就是進(jìn)行面向?qū)ο缶幊痰牡谝徊?。如果我們仔?xì)觀察身邊的對(duì)象,我們會(huì)注意到,不同的對(duì)象,他們的狀態(tài)和行為會(huì)存在很大的差別,比如你身邊同學(xué)的狀態(tài)和行為就和你所使用的電腦的狀態(tài)和行為截然不同。有些對(duì)象,它有可能還包含有其它的對(duì)象,比如一輛汽車是一個(gè)對(duì)象,它的四個(gè)輪子也是一種對(duì)象。這些現(xiàn)實(shí)生活中觀察到的例子都可以用面向?qū)ο缶幊痰男g(shù)語(yǔ)來(lái)描述。面向?qū)ο缶幊讨械摹皩?duì)象”,和現(xiàn)實(shí)生活中的對(duì)象在概念上是非常類似的。面向?qū)ο缶幊讨械膶?duì)象也有狀態(tài)和行為。一個(gè)對(duì)象把它的狀態(tài)保存在域中,通過(guò)方法表現(xiàn)對(duì)象所擁有的行為。對(duì)象的方法可以操作一個(gè)它自己的內(nèi)部狀態(tài)。方法是對(duì)象之間通信的主要手段。在面向?qū)ο缶幊讨?,我們?yīng)該隱藏一個(gè)對(duì)象的內(nèi)部狀態(tài),對(duì)這個(gè)對(duì)象的內(nèi)部狀態(tài)的任何修改都只能通過(guò)對(duì)象對(duì)外提供的方法來(lái)完成,這就叫做封裝。以電腦顯示器為例子。顯示器有一個(gè)內(nèi)部狀態(tài)叫做分辨率。我們可以提供一個(gè)方法來(lái)改變它的分辨率。這樣使用者如何改變顯示器的分辨率,實(shí)際上是由顯示器決定的,不能夠隨心所欲。如果一個(gè)顯示器的最高分辨率為1024×768,而一個(gè)使用者試圖把它的分辨率調(diào)整為1600×1200,那么顯示器可以在它的方法里面拒絕使用者的要求。在現(xiàn)實(shí)生活中,許多對(duì)象實(shí)體都具有同樣的類型。打比方說(shuō),在大街上你會(huì)看到許多和你所駕駛的小汽車擁有同樣的商標(biāo)、同樣的外形、同樣的顏色,但是由別人駕駛的小汽車。這些小汽車都是由同一個(gè)制造商按照同一份圖紙制造,因此具有同樣的部件。在面向?qū)ο缶幊汤碚撝?,我們把你的座駕稱之為這種型號(hào)的小汽車的一個(gè)實(shí)例,而所有這種型號(hào)的小汽車稱之為你的座駕所屬的類。一個(gè)類就是在構(gòu)建一個(gè)單獨(dú)的對(duì)象時(shí)使用的模板,類模板描述一個(gè)對(duì)象所擁有的狀態(tài)和行為,也即定義了一個(gè)對(duì)象的域和方法。此外,我們還會(huì)注意到,不同種類的對(duì)象也會(huì)存在著共性。比如小汽車、自行車、電動(dòng)車他們都是車,他們都共享著車所具有的性質(zhì),比如都有車輪,都能夠行駛,都能夠剎車等。但是除了這些共有的性質(zhì)外,每一類車都有它們自己所特有的性質(zhì),比如小汽車有四個(gè)輪子,電動(dòng)車以電力推動(dòng),自行車靠人力騎行等。在面向?qū)ο缶幊汤碚撝?,通過(guò)繼承機(jī)制,允許一個(gè)類從另外一個(gè)類中繼承一些共有的性質(zhì),然后再另外加入自己所特有的性質(zhì)。比如“車”是小汽車、自行車、電動(dòng)車的共性的抽象,我們可以把“車”稱為小汽車、自行車、電動(dòng)車的超類,而小汽車、自行車、電動(dòng)車稱為“車”的子類,它們都繼承了車的性質(zhì),然后還加入了自己特有的性質(zhì)。比如電動(dòng)車會(huì)包括一個(gè)特有的成員——充電電池。繼承可能是多層的,一類的超類,可能還有它自己的超類,多層的繼承結(jié)構(gòu),會(huì)形成一個(gè)繼承樹。從上述討論中我們已經(jīng)了解到,對(duì)象通過(guò)它們提供的方法定義了它們和外界交流的方式,換句話說(shuō),方法構(gòu)成了對(duì)象和外部世界交互的接口。舉例來(lái)說(shuō),鍵盤和鼠標(biāo)就是你和你所使用的電腦的接口,你通過(guò)鍵盤和鼠標(biāo)與隱藏在它們后面的CPU、內(nèi)存和主板打交道。點(diǎn)擊鼠標(biāo)右鍵,電腦顯示器就會(huì)彈出右鍵菜單。在Java中,接口是一個(gè)重要的面向?qū)ο蟮母拍睿x一個(gè)接口相當(dāng)于規(guī)范了一個(gè)類所允諾提供的行為,接口構(gòu)成了類和外部世界溝通的一個(gè)協(xié)議。在編譯的時(shí)候,編譯器可以通過(guò)檢查一個(gè)類是否實(shí)現(xiàn)了一個(gè)接口來(lái)確認(rèn)這個(gè)類是否遵守了它和外部世界所達(dá)成的交互協(xié)議。在Java中,如果一個(gè)類聲明它將實(shí)現(xiàn)某個(gè)接口,那么它必須實(shí)現(xiàn)這個(gè)接口所定義的所有方法,否則這個(gè)類將無(wú)法通過(guò)編譯。在編程實(shí)踐中引入面向?qū)ο蟮睦碚?,有以下的好處?/p>
(1)模塊化:可以獨(dú)立的編寫和維護(hù)一個(gè)對(duì)象的代碼而不會(huì)和系統(tǒng)中的其它對(duì)象產(chǎn)生沖突。可以安全的在系統(tǒng)中傳遞對(duì)象而不用擔(dān)心對(duì)象的內(nèi)部狀態(tài)受到非法的修改。
(2)信息隱藏:只允許外界通過(guò)對(duì)象對(duì)外提供的方法訪問(wèn)對(duì)象,可以保證一個(gè)對(duì)象的內(nèi)部實(shí)現(xiàn)細(xì)節(jié)對(duì)外是透明的。
(3)代碼重用:如果存在一個(gè)預(yù)先編寫好的對(duì)象,就可以直接使用它,而無(wú)需進(jìn)行二次開發(fā)。因?yàn)橹灰粋€(gè)對(duì)象經(jīng)過(guò)詳細(xì)的測(cè)試,它就是安全的可被重用的。
(4)易于調(diào)試:如果一個(gè)特定的對(duì)象被發(fā)現(xiàn)是有問(wèn)題的,只需把它從系統(tǒng)中隔離開來(lái),用另外一個(gè)沒(méi)有問(wèn)題的對(duì)象替換就可以了。這會(huì)大大降低調(diào)試的難度。
3.2類聲明和類體
如上所述,類是組成Java程序的基本要素。類封裝了一個(gè)對(duì)象類別的狀態(tài)和方法,它是用來(lái)創(chuàng)建對(duì)象的模板。類的基本格式如下:
class類名{
類體的內(nèi)容
}其中class是用來(lái)定義類的關(guān)鍵字,“class類名”是類的聲明部分。類體(括號(hào)之間的內(nèi)容)包含從這個(gè)類創(chuàng)建的對(duì)象在整個(gè)生命周期所需要的代碼,其中包括用于初始化新的對(duì)象的構(gòu)造方法,用于提供類和從屬于它的對(duì)象內(nèi)部狀態(tài)的域和實(shí)現(xiàn)了類及從屬于它的對(duì)象的行為方法。上述類的聲明部分是最基本的。類聲明還可以包含以下的信息:
(1)類的訪問(wèn)限制符,如public、private等。
(2)通過(guò)關(guān)鍵字extends聲明父類的名字。注意在Java中的類只能有一個(gè)直接父類。
(3)通過(guò)關(guān)鍵字implements聲明所要實(shí)現(xiàn)的接口的名字,一個(gè)類可以實(shí)現(xiàn)多個(gè)接口,多個(gè)接口的名字之間以逗號(hào)分隔。
一個(gè)復(fù)雜的類聲明的例子如下所示:
publicclassSunextendsFatherimplementsPlayable,Workable{
……
}在這個(gè)例子里面,聲明了一個(gè)公共類Sun,它的父類是Father,實(shí)現(xiàn)了兩個(gè)接口Playable和Workable。
習(xí)慣上,類名的第一個(gè)字母大寫,當(dāng)類名由幾個(gè)單詞復(fù)
合而成時(shí),每個(gè)單詞的首字母大寫。如“DateTime”、“AmercianCity”、“EuropeAndAsia”都是符合規(guī)范的類名。類體中有兩種類型的成員:
(1)類中的成員變量,也稱之為域,它們用來(lái)刻畫對(duì)象的內(nèi)部狀態(tài)。
(2)類中的方法,用來(lái)刻畫對(duì)象對(duì)外提供的行為,其中有一類方法非常特殊,它們就是構(gòu)造方法。構(gòu)造方法給定類所創(chuàng)建的對(duì)象的初始狀態(tài),供類創(chuàng)建對(duì)象時(shí)使用。我們將在后續(xù)章節(jié)對(duì)構(gòu)造方法進(jìn)行詳細(xì)的討論。其中成員變量,也即域,其聲明依照順序,由以下三部分組成:
(1)零個(gè)或多個(gè)修飾符。如public修飾符就用來(lái)表明一個(gè)域是公共的。
(2)域的數(shù)據(jù)類型。域的數(shù)據(jù)類型可以是Java中的任何一種數(shù)據(jù)類型,包括基本數(shù)據(jù)類型、對(duì)象和接口。
(3)域的名稱。域的名稱遵循一般變量的命名規(guī)則和慣例。而成員方法,其聲明依照順序,由以下六部分組成:
(1)方法的訪問(wèn)限制符和其它的修飾符。如public,private,static等。
(2)方法的返回類型,即方法返回值的數(shù)據(jù)類型。如果方法沒(méi)有返回值,則標(biāo)記為void,這其中有一種例外,就是構(gòu)造方法。構(gòu)造方法沒(méi)有返回值,即使標(biāo)記為void也是不允許的。
(3)方法的名稱。方法的名稱也遵循一般變量的命名規(guī)則和慣例,一般而言,其第一個(gè)單詞應(yīng)該是動(dòng)詞,第一個(gè)單詞的首字母小寫。而后續(xù)單詞的首字母應(yīng)該大寫。
(4)由圓括號(hào)括起來(lái)的,以逗號(hào)分隔的參數(shù)列表。
(5)有可能拋出的異常的列表。
(6)由一對(duì)大括號(hào)括起來(lái)的方法體的內(nèi)容。在例3-1中,給出了類Car的定義。類Car中兩個(gè)私有的雙精度類型域speed和weight,分別用來(lái)刻畫一輛小車的速度和重量。在定義域時(shí)我們給定了它們的默認(rèn)值。這輛小車的默認(rèn)時(shí)速為80mph,默認(rèn)重量為1.3噸。定義了兩個(gè)方法setSpeed和setWeight,分別用來(lái)修改一個(gè)小車對(duì)象的速度和重量。另外定義了兩個(gè)方法getSpeed和getWeight,分別用來(lái)獲得這輛小車的速度和重量。由于speed和weight是私有的,getSpeed和getWeight方法是我們?cè)L問(wèn)類Car實(shí)例的內(nèi)部特征的唯一方法。main方法是一個(gè)靜態(tài)的測(cè)試方法,也是應(yīng)用程序運(yùn)行的入口。在類的定義中,方法是可以重載的。方法的重載是多態(tài)性的一種,指的是一個(gè)類中可以有多個(gè)方法具有相同的名字,但是這些方法的參數(shù)必須不同。還記得我們常用的命令行輸出方法System.ou.println嗎?它有以下的重載版本:
(1)?println():直接換行。
(2)?println(booleanx):輸出一個(gè)布爾類型的數(shù)字然后
換行。
(3)?println(charx):輸出一個(gè)字符然后換行。
(4)?println(char[]x):輸出一個(gè)字符數(shù)組然后換行。
(5)?println(doublex):輸出一個(gè)雙精度類型的數(shù)字然后
換行。
(6)?println(floatx):輸出一個(gè)單精度類型的數(shù)字然后換行。
(7)?println(intx):輸出一個(gè)整型數(shù)字然后換行。
(8)?println(longx):輸出一個(gè)長(zhǎng)整型數(shù)字然后換行。
(9)?println(Objectx):輸出一個(gè)對(duì)象然后換行。
(10)?println(Stringx):輸出一個(gè)字符串然后換行。需要注意的是:所謂的參數(shù)不同指的是參數(shù)的個(gè)數(shù)不同或者參數(shù)的類型不同,方法的返回類型和參數(shù)的名字不參與比較。比如以下兩個(gè)方法不是重載,因?yàn)樗鼈儍H僅是返回類型不同:
doublegetValue(intval);
intgetValue(intval);
以下兩個(gè)方法也不是重載,因?yàn)樗鼈冎挥袇?shù)的名字不同,而參數(shù)的類型和個(gè)數(shù)都相同:
voidoutputStr(intx,inty);
voidoutputStr(inta,intb);
3.3構(gòu)造方法與對(duì)象的創(chuàng)建和使用
在類的定義中,構(gòu)造方法是一類特殊的方法,用于從類模板中創(chuàng)建對(duì)象。構(gòu)造方法的聲明和普通方法的聲明類似,只是它們使用類的名稱,而且沒(méi)有返回類型。和類中普通方法的重載類似,Java也允許一個(gè)類中有若干個(gè)構(gòu)造方法,但是這些構(gòu)造方法的參數(shù)必須不同,即參數(shù)的個(gè)數(shù)不同,或者參數(shù)的類型不同。Java編譯器可以根據(jù)構(gòu)造方法的參數(shù)數(shù)量和類型來(lái)使用不同的構(gòu)造方法,但是不能在一個(gè)類中使用兩個(gè)參數(shù)個(gè)數(shù)和類型都相同的構(gòu)造方法,這樣會(huì)引起編譯錯(cuò)誤。
【例3-2】長(zhǎng)方體類Cuboid的定義。
publicclassCuboid{
intheight=20;
intlength=30;
intdepth=10;
publicCuboid(){};
publicCuboid(inth){
height=h;
}
publicCuboid(inth,intl){
height=h;
length=l;
}
publicCuboid(inth,intl,intd){
height=h;
length=l;
depth=d;
}
}在例3-2中,給出了類Cuboid的定義。長(zhǎng)方體類Cuboid有三個(gè)域height、length和depth,分別代表一個(gè)長(zhǎng)方體的高、長(zhǎng)和深,長(zhǎng)方體的高、長(zhǎng)和深的初值分別為20、30和10。這個(gè)類里面提供了四個(gè)構(gòu)造方法。第一個(gè)構(gòu)造方法沒(méi)有參數(shù),將使用默認(rèn)的高、長(zhǎng)和深創(chuàng)建一個(gè)立方體;第二個(gè)構(gòu)造方法允許在創(chuàng)建立方體時(shí)修改它的高度;第三個(gè)構(gòu)造方法允許在創(chuàng)建立方體時(shí)修改它的高度和長(zhǎng)度;第四個(gè)構(gòu)造方法允許在創(chuàng)建立方體時(shí)同時(shí)修改它的高度、長(zhǎng)度和深度。需要注意的是,我們可以不為類提供任何的構(gòu)造方法。如果一個(gè)類的代碼沒(méi)有提供構(gòu)造方法,則在編譯的時(shí)候,Java編譯器會(huì)為這個(gè)類提供一個(gè)沒(méi)有參數(shù)的默認(rèn)構(gòu)造方法,這個(gè)默認(rèn)構(gòu)造方法不作任何域的初始化工作。但是如果我們?yōu)轭愄峁┝艘粋€(gè)以上的構(gòu)造方法,則在編譯的時(shí)候,Java編譯器不再為這個(gè)類提供沒(méi)有參數(shù)的默認(rèn)構(gòu)造方法。這在有的時(shí)候會(huì)引起混淆,所以強(qiáng)烈建議為每一個(gè)類都提供一個(gè)沒(méi)有參數(shù)的默認(rèn)構(gòu)造方法。當(dāng)使用一個(gè)類創(chuàng)建一個(gè)對(duì)象時(shí),我們也說(shuō)給出了這個(gè)類的一個(gè)實(shí)例。創(chuàng)建一個(gè)對(duì)象包括了聲明對(duì)象和為對(duì)象分配成員變量?jī)蓚€(gè)步驟。
對(duì)象聲明的一般格式為:
類名對(duì)象名1[,對(duì)象名2,對(duì)象名3,…];
如下面的兩個(gè)例子:
Cuboidcb;
Carcar1,car2,car3;
第一個(gè)例子聲明了Cuboid類的對(duì)象變量cb,第二個(gè)例子連續(xù)聲明了三個(gè)Car類的對(duì)象變量car1、car2和car3。在第一章中我們已經(jīng)知道,Java取消了在C/C++?中容易產(chǎn)生的內(nèi)存錯(cuò)誤訪問(wèn)等問(wèn)題的指針機(jī)制。但在Java中,對(duì)象變量是一種和指針變量很類似的變量。對(duì)象變量是一種“引用型”變量,和基本類型的變量完全不同?;绢愋偷淖兞恐写娣诺氖沁@個(gè)變量的值,但在對(duì)象變量中,存放的是引用對(duì)象實(shí)體的標(biāo)志,即存放對(duì)象實(shí)體所在內(nèi)存區(qū)域的首地址的地址號(hào)。當(dāng)然,Java中的引用型變量和C/C++?中的指針有著本質(zhì)的區(qū)別。Java中的引用型變量不能像指針變量那樣隨意的分配內(nèi)存地址,或通過(guò)進(jìn)行指針加減運(yùn)算在內(nèi)存中隨意游走,因此也就不會(huì)導(dǎo)致在C/C++?中容易產(chǎn)生的內(nèi)存錯(cuò)誤訪問(wèn)等問(wèn)題。在聲明了對(duì)象變量后,由于它是一種引用型變量,其中還沒(méi)有引用任何對(duì)象實(shí)體,即沒(méi)有存放任何對(duì)象實(shí)體所在內(nèi)存區(qū)域的首地址的地址號(hào)。沒(méi)有引用任何對(duì)象實(shí)體的對(duì)象變量稱之為空對(duì)象變量??諏?duì)象變量不能使用,如果程序中使用了空對(duì)象變量,則在運(yùn)行時(shí)會(huì)出現(xiàn)異常——NullPointerException。關(guān)于異常我們將會(huì)在第七章詳細(xì)介紹。因此我們?cè)诼暶鲗?duì)象變量后,要盡快的為對(duì)象變量分配對(duì)象實(shí)體。所謂對(duì)象實(shí)體就是用類模板創(chuàng)建一個(gè)對(duì)象時(shí),這個(gè)新建的對(duì)象所獲得的內(nèi)存區(qū)域。在Java中,使用new運(yùn)算符和類的構(gòu)造方法為新建的對(duì)象分配內(nèi)存,為其中的域置初值,并把對(duì)這段內(nèi)存的引用返回給對(duì)象變量,從而完成對(duì)象的實(shí)體化。new操作符后面跟著的是類模板中某一個(gè)構(gòu)造方法。比如:
Cuboidcb=newCuboid(5,10,15);
在這個(gè)例子中,使用new操作符通過(guò)調(diào)用Cuboid類(有三個(gè)參數(shù))的構(gòu)造方法,創(chuàng)建了一個(gè)Cuboid類的對(duì)象實(shí)體。并把這個(gè)對(duì)象實(shí)體的引用返回給對(duì)象變量cb。在創(chuàng)建對(duì)象之后,就可以通過(guò)對(duì)象變量操作它所引用的對(duì)象實(shí)體中的域,以及調(diào)用它所引用的對(duì)象實(shí)體中的方法來(lái)改變對(duì)象的內(nèi)部狀態(tài)。通過(guò)使用對(duì)象成員訪問(wèn)操作符“.”,就可以實(shí)現(xiàn)對(duì)一個(gè)對(duì)象的成員變量和方法的訪問(wèn)。使用對(duì)象成員訪問(wèn)操作符“.”訪問(wèn)成員變量的一般格式如下:
對(duì)象名.域名
例如以下代碼就分別對(duì)Cuboid類的域height和depth置了
初值:
cb.height=20;
cb.depth=50;也可以使用對(duì)象變量調(diào)用一個(gè)對(duì)象實(shí)體的方法。把對(duì)象實(shí)體的方法名附加在對(duì)象變量之后,中間使用對(duì)象成員訪問(wèn)操作符“.”連接。然后在小括號(hào)內(nèi)提供方法執(zhí)行所需的參數(shù)。如果這個(gè)方法不需要任何參數(shù),則使用空括號(hào)就可以了。
【例3-3】新添加了成員方法和測(cè)試入口main方法的長(zhǎng)方體類Cuboid。
publicclassCuboid{
intheight=20;
intlength=30;
intdepth=10;
publicCuboid(){};
publicCuboid(inth){
height=h;
}
publicCuboid(inth,intl){
height=h;
length=l;
}
publicCuboid(inth,intl,intd){
height=h;
length=l;
depth=d;
}
publicintcalVolume(){
returnheight*length*depth;
}
publicstaticvoidmain(String[]args){
Cuboidcb=newCuboid(10,15);
cb.depth=5;
System.out.printf(“VolumeoftheCuboid:%d\n”,
cb.calVolume());
}
}在例3-3中,類Cuboid新添加了一個(gè)返回類型為整型的方法calVolume用來(lái)計(jì)算一個(gè)長(zhǎng)方體的體積。在main方法中,通過(guò)調(diào)用Cuboid類中兩個(gè)參數(shù)的構(gòu)造方法,新建了一個(gè)Cuboid類的實(shí)體,并把實(shí)體的引用返回給對(duì)象變量cb。然后通過(guò)對(duì)象變量cb把成員變量depth的值從默認(rèn)值10修改為5。最后通過(guò)調(diào)用cb對(duì)象的CalVolume方法算出了這個(gè)長(zhǎng)方體的體積。例3-3的輸出如圖3.1所示。圖3.1例3-3的輸出結(jié)果
C++要求程序員跟蹤通過(guò)new操作符創(chuàng)建的所有對(duì)象,并在不再需要的時(shí)候顯式的銷毀它們,這是非常容易出錯(cuò)的。Java虛擬機(jī)提供了一個(gè)垃圾回收器,它定期地回收已經(jīng)不再被引用的對(duì)象實(shí)體占用的內(nèi)存。借助Java平臺(tái)的垃圾回收機(jī)制,程序員可以創(chuàng)建任意數(shù)量的對(duì)象,且不必為銷毀它們操心。但是Java虛擬機(jī)的垃圾回收器是自動(dòng)選擇執(zhí)行回收任務(wù)的時(shí)機(jī)的,在某些情況下,Java虛擬機(jī)的垃圾回收有一定的滯后性,會(huì)導(dǎo)致系統(tǒng)性能的下降。因此如果當(dāng)對(duì)象變量已經(jīng)沒(méi)有使用價(jià)值的時(shí)候,建議通過(guò)顯示將對(duì)象變量設(shè)置為特殊值null來(lái)銷毀對(duì)象引用。
3.4域/成員變量
從上述章節(jié)中,我們已經(jīng)知道,類體中可以有兩種類型的成員:域(即成員變量)和成員方法。成員變量用來(lái)刻畫類所創(chuàng)建的對(duì)象的內(nèi)部特征,成員變量又可以分為兩種:實(shí)例變量和類變量。用關(guān)鍵字static修飾的成員變量稱之為靜態(tài)變量,也即類變量;不使用關(guān)鍵字static修飾的成員變量稱之為實(shí)例變量。當(dāng)從同一個(gè)類模板創(chuàng)建多個(gè)對(duì)象時(shí),每個(gè)對(duì)象都擁有屬于它自己的實(shí)例變量的副本,這是因?yàn)槊恳粋€(gè)對(duì)象都被分配一個(gè)獨(dú)一無(wú)二的內(nèi)存空間,而這些對(duì)象的實(shí)例變量所對(duì)應(yīng)的實(shí)體位于這些內(nèi)存空間內(nèi)。因此修改一個(gè)對(duì)象的實(shí)例變量,不會(huì)影響另外一個(gè)對(duì)象的實(shí)例變量。但是有時(shí)候,我們也希望某些變量是從同一個(gè)類模板創(chuàng)建的所有對(duì)象共享的,這個(gè)時(shí)候我們就要使用類變量。一個(gè)類模板所創(chuàng)建的所有對(duì)象的類變量都被分配到同一個(gè)內(nèi)存區(qū)域,修改其中一個(gè)對(duì)象的類變量,會(huì)影響其他由這個(gè)類模板創(chuàng)建的對(duì)象相應(yīng)的類變量。為什么修改一個(gè)對(duì)象的類變量,會(huì)影響其他由這個(gè)類模板創(chuàng)建的對(duì)象相應(yīng)的類變量?這是因?yàn)轭愖兞看娣旁诤皖惸0逑嚓P(guān)聯(lián)的內(nèi)存空間,且只有一個(gè)副本。當(dāng)Java應(yīng)用程序在Java虛擬機(jī)中執(zhí)行時(shí),類的字節(jié)碼會(huì)被讀入到內(nèi)存中,構(gòu)建成類模板。通過(guò)類模板每創(chuàng)建一個(gè)新的對(duì)象實(shí)例,系統(tǒng)都會(huì)為這個(gè)新的對(duì)象實(shí)例分配一個(gè)內(nèi)存空間,這個(gè)對(duì)象所擁有的實(shí)例變量就存放在這個(gè)內(nèi)存空間中。而類變量由于只有一個(gè)副本,所以所有的對(duì)象共享著這些類變量。而且,類變量的存在與否和這些對(duì)象實(shí)例的存在與否是完全無(wú)關(guān)的。一個(gè)對(duì)象消亡了,它所擁有的所有實(shí)例變量也會(huì)隨著自動(dòng)垃圾回收而消失,但是類變量會(huì)一直存在。類變量所占據(jù)的內(nèi)存空間直到程序運(yùn)行結(jié)束才會(huì)被釋放,因此,類變量是與類相關(guān)聯(lián)的數(shù)據(jù)變量,它不僅可以通過(guò)某個(gè)對(duì)象訪問(wèn),也可以直接通過(guò)類名訪問(wèn)。與之相反,實(shí)例變量是和特定的對(duì)象實(shí)例相關(guān)聯(lián)的,只能通過(guò)對(duì)象變量訪問(wèn)。
【例3-4】Greet類,用于生成一句話,這句話的開頭是一句招呼語(yǔ),然后告訴對(duì)方自己的名字。
publicclassGreet{
publicstaticStringprefix;
publicStringname;
publicGreet(Stringn){
name=n;
}
publicvoidoutputGreetingStr(){
System.out.println(prefix+“mynameis”+name);
}
publicstaticvoidmain(String[]args){
Greet.prefix=“Hi,nicetomeetyou!”;
Greetalice_greet=newGreet(“Alice”);
Greetbob_greet=newGreet(“Bob”);
alice_greet.outputGreetingStr();圖3.2例3-4的運(yùn)行結(jié)果
bob_greet.outputGreetingStr();
alice_greet.prefix=“Hey,guys,”;
alice_greet.outputGreetingStr();
bob_greet.outputGreetingStr();
}
}圖3.2例3-4的運(yùn)行結(jié)果
Greet類運(yùn)行的結(jié)果如圖3.2所示。
在Greet類中,用于打招呼的一句話記錄在字符串類型的類變量prefix中,打招呼的人的名字記錄在字符串類型的實(shí)例變量name中,name的值在創(chuàng)建對(duì)象時(shí)由構(gòu)造方法的參數(shù)傳遞進(jìn)來(lái)。Greet類提供了outputGreetingStr方法,用于輸出打招呼的話,這句打招呼的話是由prefix和name兩個(gè)字符串合成的。上述程序從Greet類的main方法開始執(zhí)行。一開始的時(shí)候沒(méi)有任何Greet類的對(duì)象實(shí)例,但是卻可以直接通過(guò)Greet類訪問(wèn)類變量prefix,把它的值設(shè)置為“Hi,nicetomeetyou!”。然后我們創(chuàng)建了兩個(gè)Greet類的對(duì)象alice_greet和bob_greet,分別代表Alice和Bob的招呼語(yǔ)。在輸出兩個(gè)人的招呼語(yǔ)字符串后,通過(guò)以下語(yǔ)句:
alice_greet.prefix=“Hey,guys,”;
我們把類變量prefix改為了“Hey,guys,”,然后再輸出兩個(gè)人的招呼語(yǔ)字符串。從圖3.2中可以看出,盡管我們是通過(guò)alice_greet修改類變量prefix的,但是bob_greet中的類變量prefix也被更改為了“Hey,guys,”。如果一個(gè)域被修飾符final修飾,它就變成了常量。所謂常量,也就是這個(gè)域的值是不能夠被改動(dòng)的。如果程序試圖為一個(gè)常量重新賦值,則會(huì)導(dǎo)致編譯錯(cuò)誤。既然常量的值在編譯時(shí)是已知的,那么Java編譯器會(huì)在編譯時(shí),在每個(gè)常量該出現(xiàn)的地方,用常量的值替換掉該常量,因此常量不占用內(nèi)存,這也意味著在聲明常量的時(shí)候,必須給出它的初值。代碼中常量的名字習(xí)慣上用大寫字母表示,如果名稱由一個(gè)以上的單詞構(gòu)成,那么使用下劃線“_”分隔各個(gè)單詞。例3-5給出了一個(gè)使用常量的類。
【例3-5】使用常量的類的例子。在這個(gè)例子里面,使用類常量PI記錄了圓周率,這個(gè)圓周率被用于計(jì)算一個(gè)圓形的周長(zhǎng)和面積。
publicclassCircle{
privatestaticfinaldoublePI=3.1415926;
privatedoubleradius;
publicCircle(doubler){
radius=r;
}
publicdoublecalPerimeter(){
return2*PI*radius;
}
publicdoublecalArea(){
returnPI*radius*radius;
}
publicstaticvoidmain(String[]args){
Circlec=newCircle(10);
System.out.printf(“Perimeter:%f,Area:%f\n”,c.calPerimeter(),c.calArea());
}
}
3.5成員方法
除了構(gòu)造方法外,其它的成員方法又可以分類為類方法和實(shí)例方法。在方法聲明中使用關(guān)鍵字static修飾的成員方法稱之為靜態(tài)方法或類方法,而不使用關(guān)鍵字static修飾的成員方法稱之為實(shí)例方法。實(shí)例方法必須通過(guò)對(duì)象名來(lái)調(diào)用;而類方法既可以通過(guò)類名來(lái)調(diào)用,也可以通過(guò)對(duì)象名來(lái)調(diào)用。一個(gè)類中的方法可以相互調(diào)用,在方法中可以訪問(wèn)這個(gè)類的成員變量。但需要注意的是,在實(shí)例方法中,既可以訪問(wèn)實(shí)例變量和實(shí)例方法,也可以訪問(wèn)類變量和類方法;但是在類方法中,只可以訪問(wèn)類變量和類方法,不允許訪問(wèn)實(shí)例變量和實(shí)例方法。為什么會(huì)存在這樣的區(qū)別呢?這是因?yàn)?,每個(gè)對(duì)象都擁有屬于它們自己的實(shí)例變量的副本,而類變量是存放在和類模板相關(guān)聯(lián)的內(nèi)存空間中,類變量的存在與否和對(duì)象實(shí)例的存在與否是完全無(wú)關(guān)的。在調(diào)用類方法的時(shí)候,對(duì)象實(shí)例可能還不存在,因此這個(gè)對(duì)象實(shí)例所擁有的實(shí)例變量也不存在。如果允許類方法訪問(wèn)實(shí)例變量的話,那么類方法可能會(huì)訪問(wèn)尚未分配的內(nèi)存區(qū)域,產(chǎn)生越界訪問(wèn)錯(cuò)誤。而在調(diào)用實(shí)例方法的時(shí)候,它所隸屬的對(duì)象實(shí)例已經(jīng)存在,因此實(shí)例方法可以訪問(wèn)實(shí)例變量。正因?yàn)閷?shí)例方法可以訪問(wèn)實(shí)例變量,所以如果允許類方法訪問(wèn)實(shí)例方法,間接地,也可能會(huì)導(dǎo)致類方法訪問(wèn)未分配的內(nèi)存區(qū)域。所以,只有實(shí)例方法才允許訪問(wèn)一個(gè)對(duì)象的實(shí)例變量和其它的實(shí)例方法。
【例3-6】使用類方法和實(shí)例方法的例子。在這個(gè)例子里面,我們創(chuàng)建了一個(gè)Student類。Student類里面有一個(gè)初值為0的類成員變量number用來(lái)記錄學(xué)生的總數(shù)。這個(gè)類成員變量能通過(guò)類方法getNumber訪問(wèn),而實(shí)例成員變量name用來(lái)記錄每個(gè)學(xué)生的名字。Name能通過(guò)實(shí)例方法getName訪問(wèn)。在測(cè)試代碼中,創(chuàng)建了三個(gè)學(xué)生Alice、Bob和Eve。然后把學(xué)生的總數(shù)和每個(gè)學(xué)生的名字打印出來(lái)。Student類的運(yùn)行結(jié)果如圖3.3所示。圖3.3例3-6的運(yùn)行結(jié)果在定義成員方法的時(shí)候,給定的參數(shù)稱之為“形式參數(shù)”,簡(jiǎn)稱為“形參”。當(dāng)調(diào)用成員方法的時(shí)候,如果成員方法有參數(shù),則必須提供實(shí)際的參數(shù)。這種實(shí)際的參數(shù)簡(jiǎn)稱為“實(shí)參”。實(shí)參具有確定的值,在調(diào)用方法的時(shí)候,實(shí)參的值傳遞給形參。在Java中,所有的參數(shù)傳遞都是“按值傳遞”,也即是說(shuō),方法中形參的值是傳遞進(jìn)去的實(shí)參的值的一個(gè)副本。但是在Java中“按值傳遞”基本數(shù)據(jù)類型和對(duì)象數(shù)據(jù)類型參數(shù),有著細(xì)微的區(qū)別,必須對(duì)其詳細(xì)討論。3.5.1“按值傳遞”基本數(shù)據(jù)類型參數(shù)
對(duì)于基本數(shù)據(jù)類型的實(shí)參,它是按值傳遞進(jìn)方法內(nèi)部的,也即是說(shuō),在方法內(nèi)部對(duì)于參數(shù)的任何改動(dòng)都只限于這個(gè)方法的作用域內(nèi)。當(dāng)從方法返回時(shí),形參消失,它所占據(jù)的內(nèi)存區(qū)域被釋放,因此對(duì)參數(shù)所作的修改全部都會(huì)丟失。在方法執(zhí)行完畢后,實(shí)參的值不受方法內(nèi)部改動(dòng)的影響。
【例3-7】“按值傳遞”基本數(shù)據(jù)類型參數(shù)的例子。在這個(gè)例子里面,main方法定義了一個(gè)局部變量param,它的初值為12。param作為實(shí)參傳遞進(jìn)方法changeParam中,在方法changeParam內(nèi)部,形參param執(zhí)行了自加操作。但是從程序的輸出結(jié)果,我們會(huì)發(fā)現(xiàn),形參所執(zhí)行的自加操作,在方法執(zhí)行結(jié)束后,并沒(méi)有影響到main方法中的實(shí)參param的值。PassPrimitiveParam類的運(yùn)行結(jié)果如圖3.4所示。圖3.4例3-7的運(yùn)行結(jié)果另外值得注意的是,向基本數(shù)據(jù)類型的形參所傳遞的實(shí)參值,它的級(jí)別不可以高于對(duì)應(yīng)的形參的級(jí)別。比如可以傳遞一個(gè)float類型的實(shí)參值給一個(gè)double類型的形參,卻不可以傳遞一個(gè)float類型的實(shí)參值給一個(gè)int類型的形參。如果必須要把高級(jí)別的實(shí)參值傳遞給低級(jí)別的形參,必須要在傳值前進(jìn)行強(qiáng)制類型轉(zhuǎn)換,把實(shí)參值轉(zhuǎn)換為形參的類型,否則就會(huì)發(fā)生編譯錯(cuò)誤。3.5.2“按值傳遞”對(duì)象數(shù)據(jù)類型參數(shù)
對(duì)象數(shù)據(jù)類型的實(shí)參也是按值傳遞進(jìn)方法的,也即是說(shuō),在方法內(nèi)部對(duì)于對(duì)象數(shù)據(jù)類型參數(shù)的任何改動(dòng)都只限于這個(gè)方法的作用域內(nèi)。在方法執(zhí)行完畢后,實(shí)參的值不受方法內(nèi)部改動(dòng)的影響。但需要注意的是,正如我們?cè)谇懊嬲鹿?jié)所提到的,對(duì)象變量是一種“引用型”的變量,在對(duì)象變量中,存放的是對(duì)象實(shí)體的引用。因此如果通過(guò)對(duì)象數(shù)據(jù)類型的形參,在方法內(nèi)部對(duì)形參所引用的實(shí)體進(jìn)行修改,其改動(dòng)在方法執(zhí)行完畢后會(huì)保留下來(lái)。但是,畢竟在Java中只有按值傳遞,沒(méi)有按引用傳遞,因此如果直接修改對(duì)象變量類型的形參,比如說(shuō)把一個(gè)新的對(duì)象實(shí)體的引用復(fù)制給對(duì)象數(shù)據(jù)類型的形參,則這種修改在方法執(zhí)行完畢后不會(huì)被保留下來(lái)。
【例3-8】“按值傳遞”對(duì)象數(shù)據(jù)類型參數(shù)的例子。在這個(gè)例子里面,main方法定義了一個(gè)MyObject對(duì)象類型的局部變量mo,其初始的內(nèi)部狀態(tài)innerStatus為12。mo作為實(shí)參傳遞給方法changeParam1的對(duì)應(yīng)形參param。在方法changeParam1內(nèi)部,通過(guò)形參param對(duì)對(duì)象實(shí)體的內(nèi)部狀態(tài)innerStatus執(zhí)行了自加操作。從程序的輸出結(jié)果,我們會(huì)發(fā)現(xiàn),在方法執(zhí)行結(jié)束后,main方法中的實(shí)參mo的內(nèi)部狀態(tài)innerStatus確實(shí)由12變?yōu)榱?3。但是與之相反的一個(gè)例子是,mo作為實(shí)參也傳遞給方法changeParam2的對(duì)應(yīng)形參param。在方法changeParam2內(nèi)部,創(chuàng)建了一個(gè)新的MyObject的實(shí)體,并把它的引用賦值給了形參param,從程序的輸出結(jié)果,我們會(huì)發(fā)現(xiàn),在方法執(zhí)行結(jié)束后,param的改變并沒(méi)有影響到main方法中的實(shí)參mo。PassObjectParam類的運(yùn)行結(jié)果如圖3.5所示。圖3.5例3-8的運(yùn)行結(jié)果3.6this關(guān)鍵字
this是Java中一個(gè)重要的關(guān)鍵字,它代表對(duì)當(dāng)前對(duì)象的一個(gè)引用,也即被調(diào)用的方法或構(gòu)造器所隸屬的對(duì)象。通過(guò)使用this關(guān)鍵字,可以在實(shí)例方法或構(gòu)造方法中引用當(dāng)前對(duì)象的成員變量或成員方法。必須注意的是,this關(guān)鍵字不能出現(xiàn)在類方法中,這是因?yàn)樵谡{(diào)用類方法的時(shí)候,對(duì)象實(shí)例可能還不存在,this引用可能為空。3.6.1在實(shí)例方法中使用this
在前面章節(jié)已經(jīng)討論過(guò),在類的實(shí)例方法中可以訪問(wèn)類的成員變量。實(shí)際上,完整的在實(shí)例方法中訪問(wèn)成員變量的格式為:
this.?成員變量名
在不引起混淆的前提下,直接通過(guò)實(shí)例成員變量名就可以在實(shí)例方法中訪問(wèn)它們。但是在一個(gè)實(shí)例方法中,可能存在和實(shí)例成員變量同名的局部變量和參數(shù),在這個(gè)時(shí)候,必須顯式的使用this關(guān)鍵字訪問(wèn)實(shí)例成員變量,避免二義性。
【例3-9】在實(shí)例方法中使用this的例子。在這個(gè)例子里面,類ThisTest有兩個(gè)私有成員變量x和y,它提供了一個(gè)方法setValues為成員變量x和y賦值。但是由于這個(gè)方法的兩個(gè)參數(shù)x和y與對(duì)應(yīng)的成員變量同名,在這個(gè)方法的作用域里面,成員變量x和y被對(duì)應(yīng)的參數(shù)所覆蓋。因此必須顯式使用this關(guān)鍵字來(lái)訪問(wèn)它們。
ThisTest類的運(yùn)行結(jié)果如圖3.6所示。圖3.6例3-9的運(yùn)行結(jié)果3.6.2在構(gòu)造方法中使用this
在構(gòu)造方法中,和在類的實(shí)例方法中一樣,可以通過(guò)this關(guān)鍵字顯式的訪問(wèn)成員變量,以避免二義性。但是在構(gòu)造方法中,this關(guān)鍵字還有另外一個(gè)用途,就是可以使用this關(guān)鍵字調(diào)用同一個(gè)類中的另一個(gè)構(gòu)造方法。但是必須注意的是,如果在構(gòu)造方法中使用this關(guān)鍵字調(diào)用其它的構(gòu)造方法,則這個(gè)語(yǔ)句必須放在構(gòu)造方法實(shí)現(xiàn)語(yǔ)句中的第一行。
【例3-10】在構(gòu)造方法中使用this的例子。在這個(gè)例子里面,Rectangle類刻畫了一個(gè)矩形。成員變量x和y代表這個(gè)矩形的左上角坐標(biāo),width和height代表矩形的寬和高。它有兩個(gè)構(gòu)造方法。第一個(gè)構(gòu)造方法接受四個(gè)參數(shù),分別給x、y、width和height賦初值。由于這個(gè)方法的四個(gè)參數(shù)和對(duì)應(yīng)的成員變量同名,因此在里面必須顯式的使用this關(guān)鍵字訪問(wèn)成員變量。第二個(gè)構(gòu)造方法接受兩個(gè)參數(shù),分別為width和height賦初值。左上角坐標(biāo)取默認(rèn)值(0,0)。因此在這個(gè)構(gòu)造方法里面,通過(guò)this(0,0,width,height)直接調(diào)用第一個(gè)構(gòu)造方法完成初始化任務(wù)。
Rectangle類的運(yùn)行結(jié)果如圖3.7所示。圖3.7例3-10的運(yùn)行結(jié)果
3.7訪問(wèn)權(quán)限
對(duì)于一個(gè)類而言,它的實(shí)例方法總是可以訪問(wèn)該類中的實(shí)例變量和類變量,調(diào)用該類中的實(shí)例方法和類方法;它的類方法總是可以訪問(wèn)該類中的類變量,調(diào)用該類中的其它類方法。但是一個(gè)類,是否可以使用另一個(gè)類的某一個(gè)成員變量或某一個(gè)成員方法呢?這是由訪問(wèn)權(quán)限修飾符決定的。如果一個(gè)類的訪問(wèn)權(quán)限修飾符為public,則這個(gè)類是公共的,在這種情況下,任何位置的任何類都可以訪問(wèn)這個(gè)類。在Java中,源文件也即Java文件的名字,必須與這個(gè)源文件中的公共類名一致。如果一個(gè)類沒(méi)有訪問(wèn)權(quán)限修飾符,也是允許的。沒(méi)有訪問(wèn)權(quán)限修飾符代表著這個(gè)類采用默認(rèn)的訪問(wèn)權(quán)限,也即包私有訪問(wèn)權(quán)限。只有和這個(gè)類在同一個(gè)包中的類,才能夠訪問(wèn)它。其它包中的類不能夠訪問(wèn)具有包私有訪問(wèn)權(quán)限的類。(關(guān)于包的概念,我們將在3.9節(jié)討論)3.7.1public訪問(wèn)權(quán)限修飾符
用關(guān)鍵字public修飾的成員變量和方法被稱為公有變量和公有方法。對(duì)于公有變量和公有方法,在任何地方,都可以通過(guò)使用對(duì)象成員訪問(wèn)操作符“.”訪問(wèn)它們。也即是,公有變量和公有方法無(wú)論在同一個(gè)類內(nèi)部,處于同一個(gè)包的其它類里面,或者處于不同包的其它類里面,都可以被訪問(wèn)但需通過(guò)對(duì)象成員訪問(wèn)操作符。3.7.2private訪問(wèn)權(quán)限修飾符
用關(guān)鍵字private修飾的成員變量和方法被稱為私有變量和私有方法。對(duì)于私有變量和私有方法,只有在本類中創(chuàng)建的該類的對(duì)象才能訪問(wèn)自己的私有變量和私有方法,在另外一個(gè)類中創(chuàng)建的對(duì)象,是不能夠訪問(wèn)該類的對(duì)象的私有變量和私有方法的。在編寫一個(gè)類的代碼的時(shí)候,如果不希望將來(lái)外部能夠通過(guò)這個(gè)類生成的對(duì)象直接訪問(wèn)內(nèi)部的成員變量和成員方法,就應(yīng)該將其設(shè)置為私有的。在面向?qū)ο缶幊虒?shí)踐中,一個(gè)實(shí)體只應(yīng)該對(duì)外暴露它希望外部知道的入口,而隱藏內(nèi)部的屬性,防止非法的訪問(wèn)。在Java中,類里面希望外部知道的入口應(yīng)該被標(biāo)記為public,而需要隱藏的內(nèi)部屬性標(biāo)記為private,這是封裝性的一種體現(xiàn)。
【例3-11】公有成員變量和私有成員變量的例子。在這個(gè)例子里面,實(shí)現(xiàn)了一個(gè)賬戶類Account。Account類中的屬性money是內(nèi)部屬性,不希望出現(xiàn)外部的非法訪問(wèn),因此Account類提供了兩個(gè)公有方法getMoney和setMoney分別用來(lái)取得賬戶中的金額和修改賬戶中的金額。在測(cè)試類Transaction中,只能通過(guò)公有方法訪問(wèn)一個(gè)賬戶的內(nèi)部金額,不能直接訪問(wèn)money屬性。3.7.3protected訪問(wèn)權(quán)限修飾符
用關(guān)鍵字protected修飾的成員變量和方法被稱為受保護(hù)的變量和受保護(hù)的方法。在不牽涉到繼承的時(shí)候,有protected修飾符和無(wú)修飾符的作用是一樣的。如果一個(gè)類繼承了另外一個(gè)類,也即是說(shuō)一個(gè)類是另外一個(gè)類的子類的話,那么它能夠訪問(wèn)其父類的成員變量和成員方法,而無(wú)論這個(gè)類是否和其父類在同一個(gè)包中。3.7.4無(wú)修飾符
不用關(guān)鍵字public、private、protected修飾符修飾的成員變量和成員方法被稱為友好的變量和友好的方法。一個(gè)類里面的友好變量和友好方法,能夠被同一個(gè)包中的另一個(gè)類通過(guò)使用對(duì)象成員訪問(wèn)操作符“.”訪問(wèn),但是不能夠被不在同一個(gè)包中的其他類訪問(wèn)。
3.8嵌套類和內(nèi)部類
Java允許在一個(gè)類中定義另一個(gè)類,這樣的類被稱為嵌套類。而包含嵌套類的類被稱為這個(gè)內(nèi)部類的外部類。嵌套類是包含它的外部類的成員,因此嵌套類可以訪問(wèn)外部類的其他成員。值得注意的是,嵌套類不僅可以訪問(wèn)外部類的public、protected和受保護(hù)的成員,連private成員也是可以訪問(wèn)的。嵌套類分為兩種類型:靜態(tài)的和非靜態(tài)的。聲明為static的嵌套類被稱為靜態(tài)嵌套類,而非靜態(tài)嵌套類也被稱為內(nèi)部類。與類方法和類變量一樣,靜態(tài)嵌套類只和外部類相關(guān),和由外部類生成的實(shí)例對(duì)象無(wú)關(guān),因此靜態(tài)嵌套類不能直接訪問(wèn)外部類中定義的實(shí)例變量和方法。另一方面,與實(shí)例方法和實(shí)例變量一樣,內(nèi)部類和包含它的外部類的一個(gè)實(shí)例相關(guān)聯(lián),內(nèi)部類可以直接訪問(wèn)這個(gè)實(shí)例對(duì)象的變量和方法。但是值得注意的是,由于內(nèi)部類是和外部類的實(shí)例相關(guān)聯(lián)的,因此它不能定義任何靜態(tài)成員,比如以下的例子:
classOuterClass{
classInnerClass{
…
}
}
我們可以看到內(nèi)部類InnerClass位于外部類OuterClass之內(nèi),因此它可以直接訪問(wèn)OuterClass的成員方法和成員變量。實(shí)例化內(nèi)部類之前必須先實(shí)例化外部類,比如以下的例子:
OuterClassouterObj=newOuterClass(…);
OuterClass.InnerClassinnerObj=OuterObj.newInnerClass(…);
【例3-12】?jī)?nèi)部類的例子。在這個(gè)例子里面,IDCollection類封裝了一個(gè)整數(shù)ID的集合。在IDCollection的初始化方法中,一個(gè)整數(shù)ID數(shù)組以及它的長(zhǎng)度作為參數(shù)傳遞進(jìn)來(lái),保存在成員變量ids中。IDCollection類中有一個(gè)內(nèi)部類IDIterator,用于從頭到尾或從尾到頭遍歷ID集合。程序運(yùn)行結(jié)果如圖3.8所示。圖3.8例3-12的運(yùn)行結(jié)果
3.9包
在編程工作中,我們可能經(jīng)常會(huì)使用其他程序員提供的類和接口。很有可能出現(xiàn)這樣的情況:我們使用的兩個(gè)類或接口具有同樣的名字。比如說(shuō),程序員A和B分別向我們提供了他們編寫的同名類Car。程序員A和B各自的Car都具有它們不可替代的特點(diǎn),所以我們必須同時(shí)使用這兩個(gè)類。但是Java不允許在同一個(gè)虛擬環(huán)境中使用兩個(gè)同名類。由于程序員A和B的Car類都是早就封裝好的,并且已經(jīng)用于很多場(chǎng)合,所以我們不能要求他們更改他們自己類的名字。那該怎么辦呢?Java已經(jīng)為我們提供了一種解決方案,那就是包的機(jī)制。在Java中,把一組相關(guān)的類和接口放在同一個(gè)包里面,以便程序員查找使用類和接口、避免命名沖突和實(shí)現(xiàn)訪問(wèn)控制。比如,我們常用的基礎(chǔ)類都放在java.lang包中,而輸入輸出相關(guān)的類都放在java.io中。我們也可以把自己創(chuàng)建的類放在某個(gè)特定的
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024-2030年中國(guó)風(fēng)電機(jī)組控制系統(tǒng)發(fā)展前景與十四五投資規(guī)劃分析報(bào)告~
- 2024-2030年中國(guó)露天酒吧行業(yè)發(fā)展趨勢(shì)及經(jīng)營(yíng)創(chuàng)新模式研究報(bào)告
- 2024-2030年中國(guó)阿苯達(dá)唑咀嚼片項(xiàng)目申請(qǐng)報(bào)告
- 2024-2030年中國(guó)門座式超重機(jī)產(chǎn)業(yè)未來(lái)發(fā)展趨勢(shì)及投資策略分析報(bào)告
- 2024-2030年中國(guó)鍛材鍛件行業(yè)發(fā)展格局及未來(lái)投資潛力分析報(bào)告
- 2024-2030年中國(guó)錫冶煉行業(yè)運(yùn)營(yíng)狀況與發(fā)展?jié)摿Ψ治鰣?bào)告
- 2024-2030年中國(guó)鑄具境外融資報(bào)告
- 2024-2030年中國(guó)銀編織線產(chǎn)業(yè)未來(lái)發(fā)展趨勢(shì)及投資策略分析報(bào)告
- 2024-2030年中國(guó)銑面機(jī)行業(yè)市場(chǎng)運(yùn)營(yíng)模式及未來(lái)發(fā)展動(dòng)向預(yù)測(cè)報(bào)告
- 2024-2030年中國(guó)金融機(jī)具行業(yè)深度分析及投資規(guī)劃研究報(bào)告
- 2024-2025學(xué)年五年級(jí)科學(xué)上冊(cè)第三單元《計(jì)量時(shí)間》測(cè)試卷(教科版)
- 大學(xué)生國(guó)家安全教育智慧樹知到期末考試答案章節(jié)答案2024年
- 應(yīng)急預(yù)案演練記錄表范例
- 工程派工單模板
- 帶頸對(duì)焊法蘭尺寸與質(zhì)量
- 二氧化氯復(fù)合解堵技術(shù)
- 國(guó)家開放大學(xué)《C語(yǔ)言程序設(shè)計(jì)》形考任務(wù)1-4參考答案
- 北京市海淀區(qū)2021-2022學(xué)年七年級(jí)上學(xué)期期末考試語(yǔ)文試卷(word版含答案)
- 佛山批發(fā)市場(chǎng)匯總
- WordA4信紙(A4橫條直接打印版)
- (精選)甲醇一書一簽Word版
評(píng)論
0/150
提交評(píng)論