版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第3章類(lèi)與對(duì)象3.1面向?qū)ο蟮幕舅枷牒突靖拍?.2案例:?jiǎn)T工工資計(jì)算程序3.3類(lèi)的聲明與對(duì)象的創(chuàng)建3.4封裝性3.5繼承性3.6多態(tài)性3.7靜態(tài)成員3.8字符串3.9數(shù)組3.10包裝類(lèi)3.11編程實(shí)例 3.1面向?qū)ο蟮幕舅枷牒突靖拍?/p>
大部分傳統(tǒng)的高級(jí)程序設(shè)計(jì)語(yǔ)言(如C語(yǔ)言)都是過(guò)程化的語(yǔ)言,在軟件開(kāi)發(fā)的過(guò)程中采用自頂向下逐步細(xì)化的方法將整個(gè)程序描述為一個(gè)過(guò)程。對(duì)于小型的系統(tǒng),這種方法是可行的,但是當(dāng)系統(tǒng)規(guī)模很大、復(fù)雜度很高時(shí),用過(guò)程化方法描述變得十分困難,面向?qū)ο蟮能浖_(kāi)發(fā)方法可以很好地解決這個(gè)問(wèn)題。
目前,面向?qū)ο蟮姆椒ㄔ谲浖_(kāi)發(fā)工作中得到了廣泛的應(yīng)用,越來(lái)越多的軟件開(kāi)發(fā)工具開(kāi)始支持面向?qū)ο蟮拈_(kāi)發(fā)方法。Java語(yǔ)言就是一種面向?qū)ο蟮某绦蛟O(shè)計(jì)語(yǔ)言,要充分利用Java語(yǔ)言的特性首先應(yīng)該理解面向?qū)ο蟮幕舅枷搿?.1.1面向?qū)ο蟮幕舅枷?/p>
面向?qū)ο蟮幕舅枷胝J(rèn)為,系統(tǒng)是由若干對(duì)象構(gòu)成的,每個(gè)對(duì)象都有各自的內(nèi)部狀態(tài)和運(yùn)動(dòng)規(guī)律,不同對(duì)象之間通過(guò)消息傳送相互作用和聯(lián)系。
圖3.1是生活中看電視的一個(gè)場(chǎng)景,觀眾按下遙控器上的頻道按鈕,遙控器發(fā)出紅外信號(hào),電視機(jī)收到紅外信號(hào)后切換到相應(yīng)的頻道,播放該頻道的節(jié)目。這里有三個(gè)對(duì)象:觀眾、遙控器和電視機(jī),三個(gè)對(duì)象之間通過(guò)特定的方法相互發(fā)送消息。圖3.1看電視場(chǎng)景中的對(duì)象及消息采用對(duì)象的觀點(diǎn)看待所要解決的問(wèn)題,并將其抽象為系統(tǒng)是極其自然與簡(jiǎn)單的,因?yàn)樗先祟?lèi)的思維習(xí)慣,使得應(yīng)用系統(tǒng)更容易理解。同時(shí),由于應(yīng)用系統(tǒng)是由相互獨(dú)立的對(duì)象構(gòu)成的,使得系統(tǒng)的修改可以局部化,因此系統(tǒng)更易于維護(hù)。例如,對(duì)于一個(gè)企業(yè)的管理信息系統(tǒng),將整個(gè)系統(tǒng)描述成一個(gè)過(guò)程是難以想象的,但可以分別描述各個(gè)部門(mén)的特性及工作流程,然后描述部門(mén)之間的聯(lián)系。這里各個(gè)部門(mén)就是組成企業(yè)的對(duì)象,當(dāng)然,在描述每個(gè)部門(mén)特性時(shí)可以采用同樣的方法。3.1.2對(duì)象與類(lèi)
使用計(jì)算機(jī)軟件來(lái)模擬現(xiàn)實(shí)世界,必須使用適當(dāng)?shù)姆椒▉?lái)描述現(xiàn)實(shí)世界中的事物。面向?qū)ο蠓椒▽⒖陀^世界中的事物用一組數(shù)據(jù)和施加于該組數(shù)據(jù)上的一組操作(行為)來(lái)描述,稱為對(duì)象。
對(duì)象的描述通常由三個(gè)部分組成:
(1)私有的數(shù)據(jù)結(jié)構(gòu)。用于描述對(duì)象的內(nèi)部狀態(tài)。例如電視機(jī)內(nèi)部保存當(dāng)前的頻道、音量、圖像亮度等信息的數(shù)據(jù)結(jié)構(gòu)。
(2)處理,稱為操作或方法。它是施加于數(shù)據(jù)結(jié)構(gòu)之上的。例如電視機(jī)接收到更換頻道的紅外遙控信號(hào)后,更換頻道,修改內(nèi)部保存當(dāng)前頻道的數(shù)據(jù)。
(3)接口。這是對(duì)象可被共享的部分,消息通過(guò)接口調(diào)用相應(yīng)的操作。接口規(guī)定哪些操作是允許的,它不提供操作是如何實(shí)現(xiàn)的信息。例如電視機(jī)通過(guò)紅外接口接收指定的操作信號(hào),電視機(jī)對(duì)外的接口就是其能夠接收的紅外信號(hào)。實(shí)際上,采用面向?qū)ο蠓椒ㄟM(jìn)行系統(tǒng)分析與設(shè)計(jì)時(shí)要描述的并不是一個(gè)個(gè)具體的對(duì)象。就像電視機(jī)的設(shè)計(jì)人員設(shè)計(jì)的并不是某一臺(tái)具體的電視機(jī),而是某一個(gè)型號(hào)的電視機(jī),按照該型號(hào)的設(shè)計(jì)方案可以生產(chǎn)許多臺(tái)電視機(jī),這些電視機(jī)具有相同的特征。為了描述這種具有相同特征的對(duì)象,面向?qū)ο蠓椒ㄒ肓祟?lèi)的概念。類(lèi)是對(duì)一組具有相同特征的對(duì)象的抽象描述,所有這些對(duì)象都是這個(gè)類(lèi)的實(shí)例。對(duì)于一個(gè)具體的系統(tǒng)而言,可能存在很多具有相同特征的對(duì)象,而且通常系統(tǒng)中對(duì)象的數(shù)目是不確定的。例如,對(duì)于一個(gè)學(xué)籍管理系統(tǒng),存在許多學(xué)生對(duì)象,它們具有相同的結(jié)構(gòu)特征和行為特征,只是表示內(nèi)部狀態(tài)的數(shù)據(jù)值不同。對(duì)于學(xué)籍管理系統(tǒng),學(xué)生是一個(gè)類(lèi),而一個(gè)具體的學(xué)生則是學(xué)生類(lèi)的一個(gè)實(shí)例。一個(gè)類(lèi)的不同實(shí)例具有相同的操作或行為的集合和相同的信息結(jié)構(gòu)或?qū)傩缘亩x,但屬性值可以不同;不同的實(shí)例具有不同的對(duì)象標(biāo)識(shí)。對(duì)于學(xué)生類(lèi)中的每一個(gè)對(duì)象,描述它們所使用的數(shù)據(jù)結(jié)構(gòu)相同,但是值不同。一個(gè)類(lèi)的定義至少包含以下兩個(gè)方面的描述:
(1)該類(lèi)所有實(shí)例的屬性定義或結(jié)構(gòu)的定義。
(2)該類(lèi)所有實(shí)例的操作(或行為)的定義。
類(lèi)的概念與人們?cè)谡J(rèn)識(shí)客觀世界的事物時(shí)所采取的分類(lèi)思想相同。人們?cè)谡J(rèn)識(shí)事物時(shí)總是將具有相同特征的事物歸為一類(lèi),屬于某類(lèi)的一個(gè)事物具有該類(lèi)事物的共同特征。
在程序設(shè)計(jì)語(yǔ)言中,類(lèi)是一種數(shù)據(jù)類(lèi)型,而對(duì)象是該類(lèi)型的變量,變量名即是某個(gè)具體對(duì)象的標(biāo)識(shí)。Java語(yǔ)言程序的基本單位就是類(lèi),一個(gè)完整的Java程序是由若干個(gè)類(lèi)構(gòu)成的,每個(gè)類(lèi)由若干數(shù)據(jù)和方法構(gòu)成,一個(gè)類(lèi)的定義包含屬性(數(shù)據(jù))和方法(行為)兩部分內(nèi)容。3.1.3封裝性、繼承性與多態(tài)性
1.封裝性
對(duì)象的一個(gè)基本特性是封裝性。封裝是一種信息隱藏技術(shù),對(duì)象內(nèi)部對(duì)用戶是隱藏的,不可直接訪問(wèn);用戶只能見(jiàn)到對(duì)象封裝界面上的信息,通過(guò)對(duì)象的外部接口訪問(wèn)對(duì)象。用戶向?qū)ο蟀l(fā)送消息,對(duì)象根據(jù)收到的消息調(diào)用內(nèi)部方法作出響應(yīng)。封裝的目的在于將對(duì)象的使用者和對(duì)象的設(shè)計(jì)者分開(kāi),使用者無(wú)需知道對(duì)象內(nèi)部實(shí)現(xiàn)的細(xì)節(jié),只需要知道對(duì)象接收的消息即可。觀察一下上面所舉電視機(jī)和遙控器的例子可以發(fā)現(xiàn),電視機(jī)內(nèi)部保存了當(dāng)前電視機(jī)的狀態(tài),如頻道、音量等,觀眾可以通過(guò)電視機(jī)屏幕顯示的信息來(lái)了解其狀態(tài),而無(wú)需知道其內(nèi)部是如何運(yùn)作的,只需要通過(guò)遙控器向電視機(jī)發(fā)送操作指令即可。
Java語(yǔ)言通過(guò)類(lèi)來(lái)實(shí)現(xiàn)封裝,類(lèi)中定義的屬性和方法分為私有和公有的。私有屬性和方法不能在對(duì)象的外部訪問(wèn),只能由類(lèi)內(nèi)的方法訪問(wèn)。而在對(duì)象的外部,只能訪問(wèn)對(duì)象的公有屬性和方法,只需要知道公有屬性的數(shù)據(jù)類(lèi)型和名字以及公有方法的原型,至于這些方法是如何實(shí)現(xiàn)的對(duì)象外部并不需要知道。對(duì)象的封裝特性可以提高模塊之間的獨(dú)立性,使得系統(tǒng)易于調(diào)試和維護(hù)。在電視機(jī)的例子中,電視機(jī)和遙控器是兩個(gè)相互獨(dú)立的對(duì)象,電視機(jī)和遙控器的設(shè)計(jì)人員確定電視機(jī)所接收的紅外信號(hào)的數(shù)據(jù)格式后,可以分別設(shè)計(jì)電視機(jī)和遙控器,不管電視機(jī)的設(shè)計(jì)方案如何修改,只要其所接收紅外信號(hào)的數(shù)據(jù)格式不變,遙控器設(shè)計(jì)人員便無(wú)需修改其設(shè)計(jì)
方案。
2.繼承性
人們?cè)趯?duì)客觀世界的事物進(jìn)行描述時(shí),經(jīng)常采取分類(lèi)的方法。類(lèi)是有層次的,即某個(gè)大類(lèi)的事物可能分為若干小類(lèi),而這些小類(lèi)又可能分為若干個(gè)更小的類(lèi)。
面向?qū)ο蠓椒ú杉{了事物分類(lèi)的層次思想,在描述類(lèi)的時(shí)候,某些類(lèi)之間具有結(jié)構(gòu)和行為的共性。例如,描述教師與學(xué)生時(shí)均需描述姓名、年齡、身高、體重等屬性,將這些共性抽取出來(lái),形成一個(gè)單獨(dú)的類(lèi)——人,用于描述教師類(lèi)和學(xué)生類(lèi)的共性。類(lèi)人的結(jié)構(gòu)特征和行為特征可以被多個(gè)相關(guān)的類(lèi)共享,教師類(lèi)和學(xué)生類(lèi)繼承了類(lèi)人的結(jié)構(gòu)和行為特征。
Java語(yǔ)言支持類(lèi)的繼承,可以從一個(gè)類(lèi)中派生出一個(gè)新的類(lèi),原來(lái)的類(lèi)稱為超類(lèi)或父類(lèi),新類(lèi)稱為超類(lèi)的子類(lèi)或派生類(lèi)。子類(lèi)的對(duì)象具有超類(lèi)對(duì)象的特征,同時(shí)又有其自身特有的特征。子類(lèi)又可以派生出新的子類(lèi),子類(lèi)的子類(lèi)也稱為派生類(lèi)。
利用類(lèi)之間的繼承關(guān)系,可以簡(jiǎn)化類(lèi)的描述,提高軟件代碼的可重用性。在設(shè)計(jì)一個(gè)新類(lèi)時(shí),不必從頭設(shè)計(jì)編寫(xiě)全部的代碼,可以通過(guò)從已有的具有類(lèi)似特性的類(lèi)中派生出一個(gè)類(lèi),繼承原有類(lèi)中的部分特性,再加上所需的新特性。另外,人們?cè)趯?duì)客觀世界的事物分類(lèi)時(shí),一個(gè)事物可能屬于多個(gè)類(lèi),具有多個(gè)類(lèi)的特性。例如一個(gè)黑人學(xué)生,他既屬于學(xué)生類(lèi),又屬于黑人類(lèi)。這種情形在面向?qū)ο蠓椒ㄖ蟹Q為多繼承,即一個(gè)類(lèi)同時(shí)從多個(gè)類(lèi)中派生出來(lái),此時(shí)類(lèi)的層次結(jié)構(gòu)是網(wǎng)狀的。
Java語(yǔ)言為了不使語(yǔ)法過(guò)于復(fù)雜,不支持多繼承,只允許子類(lèi)有一個(gè)超類(lèi),稱為單繼承。不過(guò)Java語(yǔ)言提供了接口機(jī)制,可以在一定程度上模擬多繼承。
3.多態(tài)性
多態(tài)性是面向?qū)ο笙到y(tǒng)的又一重要特性。所謂多態(tài),即一個(gè)名詞可具有多種語(yǔ)義,如一個(gè)方法名有多種功能,或者相同的接口有多種實(shí)現(xiàn)方法。就電視機(jī)的例子來(lái)說(shuō),采用同樣的操作來(lái)降低音量,不同型號(hào)的電視機(jī)其內(nèi)部實(shí)現(xiàn)的方法各不相同,對(duì)不同的電視機(jī)對(duì)象發(fā)送同樣的消息“降低音量”,不同的電視機(jī)對(duì)象執(zhí)行不同的操作。
在Java語(yǔ)言中,多態(tài)性通過(guò)方法的重載、覆蓋和接口來(lái)實(shí)現(xiàn)。方法的重載是指多個(gè)方法具有相同的名稱,但各個(gè)方法的參數(shù)表不同,即參數(shù)的類(lèi)型和參數(shù)的數(shù)量不同。有關(guān)重載的問(wèn)題本書(shū)將在3.6.1節(jié)討論。
覆蓋是指類(lèi)派生過(guò)程中,子類(lèi)與超類(lèi)的方法不僅名稱相同,參數(shù)也完全相同,但它們的功能不同,這時(shí)子類(lèi)中的方法覆蓋了超類(lèi)中同名的方法。
接口實(shí)際上是一種特殊的類(lèi),只給出方法的名稱、參數(shù)和返回值的類(lèi)型,方法的具體實(shí)現(xiàn)在實(shí)現(xiàn)該接口的類(lèi)中給出。本書(shū)3.6.3節(jié)將詳細(xì)介紹Java語(yǔ)言中接口的使用方法。
多態(tài)性使得方法的調(diào)用更加容易、靈活和方便。
3.2案例:?jiǎn)T工工資計(jì)算程序
本章將介紹Java語(yǔ)言中面向?qū)ο蟮幕菊Z(yǔ)法,通過(guò)不斷完善員工工資計(jì)算案例的功能,逐步介紹Java語(yǔ)言中類(lèi)的定義、對(duì)象的創(chuàng)建及其封裝性、繼承性和多態(tài)性。
員工工資計(jì)算程序所需實(shí)現(xiàn)的功能描述如下:某公司按周付給員工工資。公司有三種類(lèi)型的員工:固定工資員工,他們無(wú)論每周工作時(shí)間長(zhǎng)短均付給固定的薪水;鐘點(diǎn)工,按小時(shí)付工資和加班費(fèi);傭金員工,其工資按銷(xiāo)售額提成。該公司希望通過(guò)一個(gè)Java程序?qū)崿F(xiàn)不同類(lèi)型工資的計(jì)算,輸入員工的類(lèi)型和相關(guān)數(shù)據(jù)后計(jì)算每個(gè)員工的工資額并輸出工資列表。
最終完成程序的執(zhí)行情況如圖3.2和圖3.3所示。圖3.2輸入員工人數(shù)及工資信息圖3.3輸出員工工資表
3.3類(lèi)的聲明與對(duì)象的創(chuàng)建
3.3.1類(lèi)聲明的基本語(yǔ)法
1.類(lèi)的聲明
正如3.1節(jié)所述,在程序設(shè)計(jì)階段不可能描述某一個(gè)具體的對(duì)象,而是使用類(lèi)來(lái)描述一類(lèi)對(duì)象。對(duì)3.2節(jié)所描述的案例,我們不可能去描述某一個(gè)具體的員工所具有的特征。從該案例的描述中可以看出,所有員工分為三種類(lèi)型,可以定義三個(gè)類(lèi)分別描述固定工資員工、鐘點(diǎn)工和傭金員工。
Java語(yǔ)言類(lèi)聲明的完整語(yǔ)法很復(fù)雜,下面先介紹最簡(jiǎn)單的形式:
class類(lèi)名{
類(lèi)體
}
類(lèi)體部分定義類(lèi)的變量和方法。變量描述該類(lèi)對(duì)象的屬性,方法描述對(duì)象的行為特征,一個(gè)方法完成一個(gè)相對(duì)完整的功能,類(lèi)似于C語(yǔ)言的函數(shù)或其他語(yǔ)言子程序的概念。Java語(yǔ)言中沒(méi)有獨(dú)立的函數(shù)和過(guò)程,所有的子程序都是作為方法定義的,同樣Java語(yǔ)言也沒(méi)有其他語(yǔ)言中的全局變量。類(lèi)中定義的變量和方法都是類(lèi)的成員,Java語(yǔ)言對(duì)類(lèi)成員的訪問(wèn)有一定的權(quán)限限制。在定義屬性和方法時(shí),可以指定訪問(wèn)權(quán)限,Java中的訪問(wèn)權(quán)限有private、protected和public。如果不指定訪問(wèn)權(quán)限,則為friendly。有關(guān)權(quán)限的使用將在3.4.1中介紹。
2.變量成員的定義
Java語(yǔ)言中的變量有如下兩種:
一種是在某個(gè)方法中定義的局部變量,如第2章main方法中定義的變量,這些變量只有當(dāng)其所在的方法被調(diào)用時(shí)才存在,其作用范圍為方法或其所在的復(fù)合語(yǔ)句。第二種變量就是類(lèi)的成員,定義的一般形式為
[final][private|protected|public]類(lèi)型屬性名[=初值];
例如:
classTV{ //電視類(lèi)
intchannel; //頻道
intvolume; //音量
}
final為可選項(xiàng),用final修飾的成員變量為常量。在程序中不能改變常量的值,常量必須在定義時(shí)初始化。
private、protected、public表示訪問(wèn)權(quán)限,三者最多只能有一個(gè)存在。與局部變量一樣,成員變量也可以初始化,例如上面的電視類(lèi),頻道初始化為1,音量初始化為5,則可定義如下:
classTV{ //電視類(lèi)
intchannel=1; //頻道
intvolume=5; //音量
}
成員變量的類(lèi)型可以是Java語(yǔ)言中的任意數(shù)據(jù)類(lèi)型,包括簡(jiǎn)單類(lèi)型、數(shù)組、類(lèi)和接口。在類(lèi)中,成員變量名應(yīng)該是唯一的。
3.方法成員的定義
方法的定義形式與C語(yǔ)言的函數(shù)定義類(lèi)似,基本形式為
[private|protected|public]返回值類(lèi)型方法名([形式參數(shù)表])
{
方法體
}
這是最基本的形式,在后面的章節(jié)中還會(huì)陸續(xù)出現(xiàn)一些變化。下列代碼為電視類(lèi)增加兩個(gè)調(diào)整電視頻道的方法,這里假設(shè)頻道的范圍為0~99。classTV{ //電視類(lèi)
intchannel=1; //頻道
intvolume=5; //音量
voidincChannel() //頻道+1
{
channel=(channel+1)%100;
}
voiddecChannel() //頻道-1
{
channel=channel-1;
if(channel<0)
channel=99;
}
}
類(lèi)中的方法可以訪問(wèn)該類(lèi)的變量成員以及方法內(nèi)定義的局部變量和形式參數(shù)。方法內(nèi)定義的局部變量和形式參數(shù)只能在該方法內(nèi)被訪問(wèn)。方法在定義時(shí)還可能使用其他一些修飾符,例如,static、abstract、final、synchronized分別用于聲明靜態(tài)方法、抽象方法、最終方法以及同步方法,本書(shū)將在后面的章節(jié)中分別加以介紹。
另外,有時(shí)為了滿足一定的要求,需要使用其他語(yǔ)言實(shí)現(xiàn)一個(gè)方法,如對(duì)硬件直接進(jìn)行某些操作或訪問(wèn)本地操作系統(tǒng)的系統(tǒng)功能,可以使用native修飾符聲明一個(gè)本地方法。native方法不能移植,只能用于指定的運(yùn)行平臺(tái)。
4.方法的調(diào)用
定義一個(gè)類(lèi)后,我們可以創(chuàng)建對(duì)象,調(diào)用方法。方法的調(diào)用相當(dāng)于給對(duì)象發(fā)送消息,因此需要首先指定接收消息的對(duì)象。下面的例子使用了上面的電視類(lèi):
classTVApp{
publicstaticvoidmain(String[]args)
{
TVaTV=newTV(); //買(mǎi)來(lái)一臺(tái)電視機(jī)
aTV.incChannel(); //按下遙控器上頻道增加的按鈕,向電視機(jī)發(fā)送消息
}
}
語(yǔ)句aTV.incChannel()調(diào)用TV類(lèi)的方法,這里aTV為T(mén)V類(lèi)的實(shí)例,方法incChannel調(diào)用時(shí)將aTV的Channel成員的值加1。
5.方法的返回值
Java語(yǔ)言中方法每一次調(diào)用可以得到返回一個(gè)值,可以用賦值語(yǔ)句將其賦給其他變量或參與運(yùn)算。方法定義時(shí)必須指定返回值類(lèi)型,如果該方法沒(méi)有返回值,必須定義為void。下面的代碼片段為電視類(lèi)增加一個(gè)獲取當(dāng)前頻道的方法。
classTV{ //電視類(lèi)
…//此處省略前面已有代碼
intgetChannel()
{
returnchannel;
}
}
正如這個(gè)例子中看到的,Java語(yǔ)言使用return語(yǔ)句從被調(diào)用的方法中返回。return語(yǔ)句的基本形式有兩種:
(1)?return表達(dá)式;或return(表達(dá)式);
(2)?return;第一種形式用于有返回值的情況,第二種形式用于無(wú)返回值的情況。對(duì)于第一種情況,return后的表達(dá)式類(lèi)型應(yīng)與聲明的返回值類(lèi)型一致,否則會(huì)產(chǎn)生編譯錯(cuò)誤。
如果某方法聲明了返回值類(lèi)型,必須保證在該方法的每一條執(zhí)行路徑都有返回值。例如下面的方法定義:
intfunc(inta,intb)
{
if(a>b)
returna-b;
}該方法的定義是錯(cuò)誤的,當(dāng)a<=b時(shí)該方法在執(zhí)行時(shí)沒(méi)有確切的返回值。這種情況在Java語(yǔ)言中是不允許的。下面的方法定義是正確的:
intfunc(inta,intb)
{
if(a>b)
returna-b;
else
returnb-a;
}
6.參數(shù)的傳遞
Java語(yǔ)言中的方法可以有參數(shù)也可以沒(méi)有參數(shù),參數(shù)類(lèi)型可以是簡(jiǎn)單數(shù)據(jù)類(lèi)型,如整型、實(shí)型、字符型和布爾型,也可以是復(fù)合類(lèi)型,如數(shù)組和自定義類(lèi)的對(duì)象。
方法被調(diào)用時(shí),必須給定實(shí)際參數(shù),實(shí)際參數(shù)的類(lèi)型應(yīng)與形式參數(shù)的類(lèi)型一致。對(duì)于簡(jiǎn)單類(lèi)型數(shù)據(jù),實(shí)際參數(shù)傳遞給形式參數(shù)時(shí)采用值傳遞;如果參數(shù)為復(fù)合類(lèi)型,則傳遞引用,此時(shí)實(shí)參、形參為同一對(duì)象。程序3.1的運(yùn)行結(jié)果可以很好地說(shuō)明這個(gè)問(wèn)題。
【程序3.1】
參數(shù)傳遞的方法。
classB{ privateintb;
intGetb(){returnb;}
voidSetb(intj){b=j;}
}
publicclassMethodParm
{
voidMethod1(intParm1,BParm2)
{
Parm1=Parm1+10;
Parm2.Setb(20);
}publicstaticvoidmain(String[]args)
{
inta=10;
Bb=newB();
b.Setb(10);
MethodParmobj=newMethodParm();
obj.Method1(a,b);
System.out.println(a);
System.out.println(b.Getb());
}
}程序運(yùn)行結(jié)果為
10
20
Method1方法有兩個(gè)形式參數(shù),其中Parm1為簡(jiǎn)單類(lèi)型,Parm2為復(fù)合類(lèi)型。Method1被調(diào)用時(shí)首先為Parm1分配空間,將實(shí)際參數(shù)a的值復(fù)制給Parm1,因此Parm1與實(shí)際參數(shù)a在內(nèi)存中分別占據(jù)不同的空間,Parm1的值改變不影響實(shí)際參數(shù)a。而實(shí)際參數(shù)b與形式參數(shù)Parm2代表同一對(duì)象,Parm2調(diào)用方法Setb并改變其變量成員的值,它實(shí)際上是改變了實(shí)參對(duì)象。
7.this
如果局部變量或形式參數(shù)與變量成員同名,在該方法體中直接使用變量名則是對(duì)局部變量或形式參數(shù)的訪問(wèn)。如果需訪問(wèn)變量成員,可通過(guò)關(guān)鍵字this來(lái)訪問(wèn)。
【程序3.2】this使用舉例。
/**
*this關(guān)鍵字使用舉例
*/
publicclassthisDemo{
publicstaticvoidmain(String[]args){
thisDemoaObj=newthisDemo(); //創(chuàng)建thisDemo類(lèi)型對(duì)象aObj
aObj.aMethod(); //調(diào)用aMethod方法
}
privateintaVar=10;
publicvoidaMethod(){
intaVar=20;
System.out.println(“變量成員aVar=”+this.aVar);
System.out.println(“局部變量aVar=”+aVar);
}
}
aMethod方法中this.aVar訪問(wèn)當(dāng)前對(duì)象的成員aVar,第二個(gè)輸出語(yǔ)句中的aVar代表方法內(nèi)部定義的局部變量aVar。Java語(yǔ)言中類(lèi)方法成員調(diào)用時(shí)必須通過(guò)該類(lèi)對(duì)象調(diào)用,例如上面程序中main方法中的語(yǔ)句:
aObj.aMethod();這里aObj為thisDemo類(lèi)對(duì)象,aMethod為thisDemo類(lèi)的方法成員,在方法成員中this指代當(dāng)前對(duì)象。在aMethod方法執(zhí)行時(shí),this指代對(duì)象aObj。再看下面的例子:
classA{
inta=3;
publicvoidPrint(){System.out.println(“a=”+a);}
}
Print方法中的a相當(dāng)于this.a,該方法中無(wú)同名的局部變量,不會(huì)引起混淆,所以無(wú)需使用this。3.3.2類(lèi)的構(gòu)造方法與對(duì)象的初始化
類(lèi)定義了一類(lèi)對(duì)象的特性,每一個(gè)對(duì)象都是相應(yīng)類(lèi)的實(shí)例。定義一個(gè)類(lèi)后,就可以定義對(duì)象,然后訪問(wèn)對(duì)象的方法和變量成員了。
1.new運(yùn)算符
Java語(yǔ)言使用new運(yùn)算符創(chuàng)建對(duì)象。例如,程序3.2中main方法定義對(duì)象的語(yǔ)句:
thisDemoaObj=newthisDemo();
創(chuàng)建了一個(gè)thisDemo類(lèi)的對(duì)象,也可以寫(xiě)為下面的形式:
thisDemoaObj;
aObj=newthisDemo();首先聲明一個(gè)thisDemo類(lèi)對(duì)象的引用aObj,與定義簡(jiǎn)單數(shù)據(jù)類(lèi)型變量不同,這里尚未創(chuàng)建thisDemo類(lèi)的對(duì)象。變量名aObj只是程序中訪問(wèn)對(duì)象的一條途徑,并不是對(duì)象本身,執(zhí)行下面的語(yǔ)句后bObj與aObj表示同一個(gè)對(duì)象:
thisDemobObj=aObj;
Java語(yǔ)言將這類(lèi)數(shù)據(jù)類(lèi)型稱為引用類(lèi)型,與C/C++中的指針相似。引用類(lèi)型變量在未賦值前,其值為null。
定義對(duì)象引用后,用new運(yùn)算符完成對(duì)象的創(chuàng)建工作,分配存儲(chǔ)空間,并對(duì)其初始化。new運(yùn)算符創(chuàng)建對(duì)象的一般方法為變量名=new類(lèi)名([構(gòu)造方法實(shí)參表]);
類(lèi)名可以是系統(tǒng)預(yù)定義的類(lèi),也可以是自定義的類(lèi)。括號(hào)中是傳遞給構(gòu)造方法的實(shí)參,用于初始化該對(duì)象。
2.構(gòu)造方法
構(gòu)造方法是一種特殊的方法,創(chuàng)建對(duì)象時(shí)被自動(dòng)調(diào)用。構(gòu)造方法的主要作用是初始化對(duì)象,如初始化對(duì)象的變量成員。程序3.2中使用賦初值的方法給變量成員aVar賦初值為10,任意一個(gè)thisDemo類(lèi)的對(duì)象在創(chuàng)建時(shí)其變量成員aVar的值均為10。有時(shí)我們并不希望這樣,例如首先定義一個(gè)學(xué)生類(lèi),然后再創(chuàng)建不同的學(xué)生對(duì)象,每個(gè)學(xué)生對(duì)象的學(xué)號(hào)等信息是不同的,應(yīng)在對(duì)象創(chuàng)建時(shí)即能賦予不同的值,此時(shí)采用變量賦初值的方法是無(wú)法實(shí)現(xiàn)的,需要采用構(gòu)造方法來(lái)實(shí)現(xiàn)。
與一般的方法不同,構(gòu)造方法的方法名與類(lèi)名相同,構(gòu)造方法沒(méi)有返回值類(lèi)型的說(shuō)明,方法體中也不可以用return語(yǔ)句帶回返回值。與其他方法相同,構(gòu)造方法可以有參數(shù)。如果一個(gè)類(lèi)定義了構(gòu)造方法,則在創(chuàng)建該類(lèi)對(duì)象時(shí)必須按照構(gòu)造方法的要求給出實(shí)參。
【程序3.3】
構(gòu)造方法舉例。
/**
*構(gòu)造方法舉例
*/
publicclassStudent{
publicStudent(StringstuNo,StringstuName){Number=stuNo;
Name=stuName;
}
publicstaticvoidmain(String[]args){
Studentstu1=newStudent("05060001","zhang"); //傳遞參數(shù)給構(gòu)造方法
Studentstu2=newStudent("05060002","li");
stu1.printInfo();
stu2.printInfo();
}privateStringNumber;
privateStringName;
publicvoidprintInfo(){
System.out.println("Number:\t"+Number);
System.out.println("Name:\t"+Name);
}
}
Java語(yǔ)言允許一個(gè)類(lèi)有多個(gè)構(gòu)造方法,只要這些方法的參數(shù)形式不同即可。例如:
classPoint{
intx,y;
Point(intx,inty){this.x=x;this.y=y;}
Point(){x=y=0;}
}
下面的語(yǔ)句在創(chuàng)建Point類(lèi)對(duì)象時(shí)分別調(diào)用不同的構(gòu)造方法:
Pointp1=newPoint(10,10);
Pointp2=newPoint();在構(gòu)造方法中可以通過(guò)this關(guān)鍵字調(diào)用該類(lèi)中其他的構(gòu)造方法。例如,上面的例子可改寫(xiě)為下面的形式:
classPoint{
intx,y;
Point(intx,inty){this.x=x;this.y=y;}
Point(){this(0,0);}
}
第二個(gè)構(gòu)造方法調(diào)用第一個(gè)構(gòu)造方法,this后面括號(hào)中的內(nèi)容為傳遞給第一個(gè)構(gòu)造方法的實(shí)參。如果該構(gòu)造方法中還有其他的語(yǔ)句,應(yīng)保證將this語(yǔ)句放在最前面。
3.對(duì)象初始化
Java語(yǔ)言提供了三種初始化對(duì)象的方法,除了上面介紹的構(gòu)造方法外,還可以采用下面兩種方法:
(1)定義變量成員時(shí)賦初值;
(2)使用類(lèi)體中的初始化程序塊。
下面的例子中使用了Java語(yǔ)言提供的三種初始化對(duì)象的方法。
【程序3.4】
對(duì)象的初始化。
//對(duì)象的初始化方法演示
classA{
intx=5;{ //初始化程序塊開(kāi)始
System.out.println(x);
x=6;
System.out.println(x);
} //初始化程序塊結(jié)束
A(inti)
{
x=i;
System.out.println(x);
}
}publicclassInitDemo
{
publicstaticvoidmain(String[]args)
{
Aa=newA(7);
}
}
程序運(yùn)行結(jié)果為
5
6
7從程序3.4的運(yùn)行結(jié)果可以看出,Java程序在創(chuàng)建對(duì)象時(shí)首先分配空間,然后按照類(lèi)中定義的成員變量的初值初始化相應(yīng)的成員,接著執(zhí)行類(lèi)中的初始化程序塊,最后執(zhí)行構(gòu)造方法。
4.對(duì)象的清除
在一些程序設(shè)計(jì)語(yǔ)言如C++?語(yǔ)言中,動(dòng)態(tài)創(chuàng)建的對(duì)象必須由程序顯式清除,釋放其所占用的內(nèi)存空間;而Java語(yǔ)言中對(duì)象的清除是自動(dòng)進(jìn)行的,當(dāng)系統(tǒng)內(nèi)存用盡或用戶在程序中調(diào)用System.gc方法時(shí),Java運(yùn)行系統(tǒng)啟動(dòng)垃圾收集器,自動(dòng)回收不再使用的對(duì)象。垃圾收集器可以自動(dòng)判斷哪些對(duì)象不再使用,例如程序片斷:
Aa=newA();
a=newA();
在內(nèi)存中創(chuàng)建了兩個(gè)A類(lèi)對(duì)象,執(zhí)行該程序片斷之后,第一次創(chuàng)建的A類(lèi)對(duì)象在程序中無(wú)法再訪問(wèn),Java垃圾收集器將自動(dòng)收回該對(duì)象占用的空間。對(duì)不再使用的對(duì)象,程序中可以將對(duì)該對(duì)象的引用賦值為null,以釋放資源。
Java語(yǔ)言允許用戶為每個(gè)類(lèi)定義一個(gè)特殊的方法finalize(),當(dāng)垃圾收集器清除該類(lèi)對(duì)象時(shí)將調(diào)用該方法,如果用戶有一些特殊的清除工作可安排在finalize()方法中。但是用戶無(wú)法預(yù)測(cè)finalize()方法被調(diào)用的時(shí)間,即使調(diào)用System.gc強(qiáng)制啟動(dòng)垃圾收集器,也可能因?yàn)槠渌蝿?wù)的優(yōu)先級(jí)高于垃圾收集任務(wù),而不能立即啟動(dòng)。因此,一些與時(shí)間相關(guān)的代碼不應(yīng)加入到finalize()方法中。3.3.3對(duì)象的使用
在對(duì)象創(chuàng)建之后,就可以使用該對(duì)象了,可以訪問(wèn)對(duì)象的變量成員和方法成員。訪問(wèn)成員的基本語(yǔ)法形式如下:
對(duì)象名.變量成員名
對(duì)象名.方法成員名([實(shí)際參數(shù)表])
前面的例子中已出現(xiàn)多個(gè)方法調(diào)用和訪問(wèn)變量成員的語(yǔ)句,這里不再舉例。
Java語(yǔ)言引入了一個(gè)與對(duì)象有關(guān)的運(yùn)算符instanceof,用來(lái)測(cè)試一個(gè)指定的對(duì)象是否是指定類(lèi)的實(shí)例,若是,返回true,否則返回false。例如:
if(obj1instanceofClass1){
}
其中,obj1為對(duì)象名,Class1為類(lèi)名。若obj1為Class1類(lèi)的對(duì)象,則執(zhí)行大括號(hào)中的語(yǔ)句。
3.3.4案例的初步實(shí)現(xiàn)
利用上面介紹的語(yǔ)法知識(shí),可以給出員工工資計(jì)算程序的一個(gè)簡(jiǎn)化實(shí)現(xiàn),下面的程序僅輸入和處理一個(gè)員工工資的信息。3.3.4案例的初步實(shí)現(xiàn)
利用上面介紹的語(yǔ)法知識(shí),可以給出員工工資計(jì)算程序的一個(gè)簡(jiǎn)化實(shí)現(xiàn),下面的程序僅輸入和處理一個(gè)員工工資的信息。
【程序3.5】
員工工資計(jì)算程序的初步實(shí)現(xiàn)。
//SalaryEmployee.java
publicclassSalaryEmployee{
privateStringname;
privatedoublesalary;publicSalaryEmployee(Stringname,doublesalary){
this.setName(name);
this.setSalary(salary);
}
publicvoidPrintSalary(){
System.out.println(getName()+"\t"+CalculateSalary());
}
publicdoubleCalculateSalary(){
returngetSalary();
}publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
=name;
}
publicdoublegetSalary(){
returnsalary;
}
publicvoidsetSalary(doublesalary){this.salary=salary;
}
}
//HourlyEmployee.java
publicclassHourlyEmployee{
publicHourlyEmployee(Stringname,doublehours,doublewage){
this.setName(name);
this.setHours(hours);
this.setWage(wage);}
privateStringname;
privatedoublehours; //小時(shí)數(shù)
privatedoublewage; //每小時(shí)工資額
publicvoidPrintSalary(){
System.out.println(getName()+"\t"+CalculateSalary());
}
publicdoubleCalculateSalary(){
returngetHours()*getWage();
}publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
=name;
}
publicdoublegetHours(){
returnhours;
}
publicvoidsetHours(doublehours){
this.hours=hours;}
publicdoublegetWage(){
returnwage;
}
publicvoidsetWage(doublewage){
this.wage=wage;
}
}
//CommisionSalary.java
publicclassCommisionEmployee{
publicCommisionEmployee(Stringname,doublerate,doublesales){
this.setName(name);
this.setRate(rate);
this.setSales(sales);
}
privateStringname;
privatedoublerate;
privatedoublesales;
publicvoidPrintSalary(){
System.out.println(getName()+"\t"+CalculateSalary());}
publicdoubleCalculateSalary(){
returngetRate()*getSales();
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
=name;
}publicdoublegetRate(){
returnrate;
}
publicvoidsetRate(doublerate){
this.rate=rate;
}
publicdoublegetSales(){
returnsales;
}publicvoidsetSales(doublesales){
this.sales=sales;
}
}
//Main.java
importjava.util.Scanner;
publicclassMain{
publicstaticvoidmain(String[]args){
//TODOcodeapplicationlogichere
Scannerinput=newScanner(System.in);
Stringname;System.out.println("請(qǐng)輸入員工類(lèi)別:1.固定工資員工2.小時(shí)工3.傭金員工");
intchoice=input.nextInt();
input.nextLine();
switch(choice)
{
case1:
System.out.println("輸入員工的姓名,工資額:");
name=input.nextLine();
doublesalary=input.nextDouble();SalaryEmployeeaSEmployee=newSalaryEmployee(name,salary);
aSEmployee.PrintSalary();
break;
case2:
System.out.println("輸入員工的姓名,小時(shí)數(shù)和每小時(shí)工資額:");
name=input.nextLine();
doublehours=input.nextDouble();
doublewage=input.nextDouble();HourlyEmployeeaHEmployee=newHourlyEmployee(name,hours,wage);
aHEmployee.PrintSalary();
break;
case3:
System.out.println("輸入員工的姓名,傭金比例和銷(xiāo)售額:");
name=input.nextLine();
doublerate=input.nextDouble();
doublesales=input.nextDouble();CommisionEmployeeaCEmployee=newCommisionEmployee(name,rate,sales);
aCEmployee.PrintSalary();
break;
default:
System.out.println("輸入錯(cuò)誤");
break;
}
}
} 3.4封裝性
3.4.1成員的訪問(wèn)權(quán)限
在訪問(wèn)對(duì)象的方法或成員時(shí),存在一個(gè)訪問(wèn)權(quán)限的問(wèn)題,即對(duì)象之間和對(duì)象內(nèi)部哪些成員是可以訪問(wèn)的,哪些是不可以訪問(wèn)的。我們?cè)诳措娨晻r(shí)不可能直接操作電視機(jī)內(nèi)部的電子元件來(lái)改變頻道和音量,而是通過(guò)遙控器或電視機(jī)面板上的按鈕來(lái)要求電視機(jī)改變頻道和音量。3.3節(jié)中電視類(lèi)(TV)用channel和volume兩個(gè)變量來(lái)描述當(dāng)前的頻道和音量,不希望在TV類(lèi)的外部直接改變channel和volume變量的值,而是通過(guò)調(diào)用TV類(lèi)的某些方法來(lái)改變這兩個(gè)變量的值,這樣可以避免channel和volume被改變?yōu)殄e(cuò)誤的值。前面例子中通過(guò)incChannel和decChannel方法來(lái)改變channel的值,可以保證channel的值在0~99范圍之內(nèi)。
Java語(yǔ)言中,限定成員的訪問(wèn)權(quán)限是通過(guò)定義變量和方法時(shí)加上訪問(wèn)權(quán)限修飾符來(lái)實(shí)現(xiàn)的。表3.1是Java語(yǔ)言中類(lèi)的成員的訪問(wèn)范圍,其中關(guān)鍵字friendly并不出現(xiàn)在程序中,當(dāng)一個(gè)變量或方法定義沒(méi)有使用訪問(wèn)權(quán)限修飾符時(shí),其訪問(wèn)權(quán)限即為friendly。表3.1類(lèi)的成員的訪問(wèn)范圍表3.1中,√表示允許訪問(wèn),√*?表示訪問(wèn)時(shí)有一定的限制條件。包及子類(lèi)的訪問(wèn)權(quán)限本書(shū)將在3.4.2節(jié)和3.5節(jié)詳細(xì)介紹,這里首先介紹同一包中沒(méi)有繼承關(guān)系的類(lèi)之間成員訪問(wèn)的權(quán)限。
同一包中沒(méi)有繼承關(guān)系的類(lèi)之間成員訪問(wèn)的權(quán)限比較簡(jiǎn)單,類(lèi)的方法成員可以訪問(wèn)所在類(lèi)的其他方法成員和變量成員,而類(lèi)的外部不可以直接訪問(wèn)private成員。下面修改一下前面的電視類(lèi),將channel和volume變量限定為只能在類(lèi)內(nèi)訪問(wèn),代碼見(jiàn)程序3.6?!境绦?.6】成員訪問(wèn)權(quán)限。
//成員訪問(wèn)權(quán)限TV.java
publicclassTV{
privateintchannel=1;
privateintvolume=5;
publicvoidincChannel(){
setChannel((getChannel()+1)%100);
}publicvoiddecChannel(){
setChannel(getChannel()-1);
if(getChannel()<0)
setChannel(99);
}
publicvoidshowChannel(){
System.out.println("Channel"+getChannel());
}
publicintgetChannel(){
returnchannel;
}publicvoidsetChannel(intchannel){
this.channel=channel;
}
publicintgetVolume(){
returnvolume;
}
publicvoidsetVolume(intvolume){
if(volume>=0&&volume<=20)
this.volume=volume;
}
}
//主程序Main.java
publicclassMain{
publicstaticvoidmain(String[]args){
TVaTV=newTV();
aTV.showChannel();
aTV.incChannel();
}
}如果不將channel定義為private變量,則在main方法中下面的語(yǔ)句是合法的:
aTV.channel=100;
這樣的語(yǔ)句將導(dǎo)致aTV的channel變量值不合法。程序3.6中將channel定義為private變量,則上面這條語(yǔ)句在編譯階段即被視為是錯(cuò)誤的。3.4.2包的使用
Java程序編譯后,每一個(gè)類(lèi)和接口都生成一個(gè)獨(dú)立的class文件。對(duì)于一個(gè)大型程序,由于類(lèi)和接口的數(shù)量很大,如果將它們?nèi)旁谝黄?,則往往顯得雜亂無(wú)章,難于管理。Java語(yǔ)言提供了一種解決該問(wèn)題的方法:將類(lèi)和接口放在不同的包中。
1.包的概念
一個(gè)包由一組類(lèi)和接口組成,包內(nèi)還可以有子包,類(lèi)似于文件系統(tǒng)的目錄(文件夾)。實(shí)際上,Java系統(tǒng)就是使用文件夾來(lái)存放包的,一個(gè)包對(duì)應(yīng)一個(gè)文件夾,文件夾下有若干個(gè)class文件和子文件夾。當(dāng)要使用其他包內(nèi)的類(lèi)時(shí),可以使用import語(yǔ)句引入其他包內(nèi)的類(lèi)。本書(shū)前面例子中多次出現(xiàn)了import語(yǔ)句,例如:
importjava.math.*;
這里,java為包名,math為java包內(nèi)的子包,*?表示該包中的所有類(lèi),該語(yǔ)句引入了java.math包中的所有類(lèi)。java包中的子包lang是自動(dòng)引入的,無(wú)需使用import語(yǔ)句引入該包,前面提到的String、Sytem等類(lèi)均在該包中定義。
java包是Sun公司使用Java語(yǔ)言開(kāi)發(fā)的類(lèi)的集合,是隨Java運(yùn)行系統(tǒng)提供的,Java語(yǔ)言的很多功能依賴于該包中的類(lèi)。目前的Java虛擬機(jī)通常將java包以一種壓縮文件的形式存儲(chǔ)在特定的目錄中,運(yùn)行類(lèi)庫(kù)包的根目錄可以由環(huán)境變量CLASSPATH設(shè)定。
import也可以引入特定的類(lèi),只要用類(lèi)名取代上面例子里的*即可。例如:
importjava.awt.Graphics;
包的使用可以避免名字沖突,每一個(gè)類(lèi)和接口的名字都包含在某個(gè)包中,不同的包中可以有同名的類(lèi)和接口。在程序中使用同名類(lèi)時(shí),可以加上包名以免引起歧義,例如java.awt.Button表示java.awt包中的Button類(lèi),此時(shí)無(wú)需使用import語(yǔ)句引入該類(lèi)。
另外還應(yīng)注意,使用import語(yǔ)句引入某個(gè)包中的所有類(lèi)時(shí)并不包括該包的子包中的類(lèi)。
2.包的封裝作用
Java語(yǔ)言的包還具有一定的封裝作用,可以限定某些類(lèi)只能被其所在包中的類(lèi)訪問(wèn),而不能被包外的其他類(lèi)訪問(wèn)。正如電視機(jī)設(shè)計(jì)過(guò)程中需要用很多集成電路,這些集成電路本身是封裝好的模塊,外部只能通過(guò)其外部的引腳訪問(wèn),而不能訪問(wèn)其內(nèi)部,這些集成電路對(duì)最終用戶來(lái)講也應(yīng)該是不可見(jiàn)的,它們只能被設(shè)計(jì)維修人員訪問(wèn)。
Java語(yǔ)言規(guī)定只能使用其他包中公有(public)的類(lèi)和接口,即在該類(lèi)定義時(shí),使用了public修飾符,例如程序3.6的TV類(lèi)。從表3.1中可以看出:使用其他包中的類(lèi)時(shí),如果類(lèi)之間沒(méi)有繼承關(guān)系,只能訪問(wèn)該類(lèi)的public成員;同一個(gè)包中的類(lèi)除了private成員外,其他的成員均可以訪問(wèn)。
3.包的定義
如果希望將程序中不同的類(lèi)放在多個(gè)不同的包中,可以首先在程序的當(dāng)前目錄中創(chuàng)建相應(yīng)的子目錄,然后將相應(yīng)的源文件放入對(duì)應(yīng)的文件夾,分別編譯,同時(shí)應(yīng)在源文件前面加上相應(yīng)的包定義語(yǔ)句。
包定義語(yǔ)句的格式為
package包名;
注意:該語(yǔ)句必須放在程序源文件的開(kāi)始,前面不能有注釋語(yǔ)句之外的任何語(yǔ)句。程序3.7是一個(gè)使用包的完整的例子,該程序由兩個(gè)文件構(gòu)成,放在不同的包中。
【程序3.7】
包的定義與使用。
//PackageApplet.java
importjava.awt.*;
importjava.applet.*;
importMyPackage.display.displayclass; //引入displayclass類(lèi)publicclassPackageAppletextendsApplet
{
publicvoidpaint(Graphicsg)
{
Fontfont=newFont("TimesRoman",Font.PLAIN,24);
g.setFont(font);
displayclassmyclass=newdisplayclass();
Strings=myclass.GetDisplayText();
g.drawString(s,60,80);
}}
//MyPackage\display\displayclass.java
packageMyPackage.display; //包定義語(yǔ)句
publicclassdisplayclass
{
publicStringGetDisplayText(){
return"DisplayText";
}
} 3.5繼承性
3.1.3節(jié)介紹了面向?qū)ο蠓椒ǖ闹匾匦浴^承性,利用繼承性可以提高代碼的可重用性,提高軟件開(kāi)發(fā)的生產(chǎn)率。例如員工工資計(jì)算程序中無(wú)論是固定工資員工還是鐘點(diǎn)工和傭金員工,都需要輸出其工資信息,利用繼承性只需在超類(lèi)中定義如何輸出工資信息即可,而無(wú)需針對(duì)每種類(lèi)型的員工分別實(shí)現(xiàn)該功能。
3.5.1子類(lèi)的定義
Java語(yǔ)言支持繼承機(jī)制,在定義類(lèi)時(shí)通過(guò)關(guān)鍵字extends指定超類(lèi)的名稱即可。子類(lèi)定義的基本語(yǔ)法形式為
class子類(lèi)名extends超類(lèi)名{
}
Java語(yǔ)言不支持多繼承,因此超類(lèi)名只有一個(gè)。子類(lèi)繼承超類(lèi)的特性,也可以通過(guò)定義新的成員修改超類(lèi)的特性或增加新的特性。例如:
classPoint{
privateintx=0,y=0;
publicintgetX(){returnx;}
publicvoidsetX(intx){this.x=x;} publicintgetY(){returny;}
publicvoidsetY(inty){this.y=y;}
}
classColorPointextendsPoint{ //從Point派生出ColorPoint
privateintcolor=0; //增加新的變量
publicintgetColor(){returncolor;}
publicvoidsetColor(intcolor){this.color=color;}
}
Java語(yǔ)言在為子類(lèi)對(duì)象分配空間時(shí),不僅為子類(lèi)中新定義的成員分配空間,同時(shí)也為超類(lèi)中定義的成員(包括public、protected、private以及friendly成員)分配空間,在一定程度上可以認(rèn)為一個(gè)子類(lèi)對(duì)象內(nèi)部包含一個(gè)超類(lèi)對(duì)象。
Java語(yǔ)言允許將一個(gè)子類(lèi)對(duì)象作為超類(lèi)對(duì)象使用,當(dāng)需要時(shí)可以進(jìn)行隱含的類(lèi)型轉(zhuǎn)換。例如一個(gè)方法的形式參數(shù)定義為超類(lèi)對(duì)象,在調(diào)用時(shí)可以將子類(lèi)對(duì)象作為實(shí)際參數(shù)。
publicclassMain{
staticvoidDisplayPoint(PointaPoint){ //形式參數(shù)為Point類(lèi)型 System.out.println("x="+aPoint.getX()+"\ty="+aPoint.getY());
}
publicstaticvoidmain(Stringarg[])
{
ColorPointaPoint=newColorPoint();
DisplayPoint(aPoint); //實(shí)際參數(shù)為ColorPoint類(lèi)型
}
}
Java語(yǔ)言中的各種類(lèi)型的對(duì)象都可以當(dāng)作Object類(lèi)的對(duì)象使用,Object類(lèi)中定義了Java語(yǔ)言對(duì)象的基本特性,如果在定義一個(gè)類(lèi)時(shí)沒(méi)有用extends關(guān)鍵字指定超類(lèi),則該類(lèi)的超類(lèi)為Object。
超類(lèi)中定義的成員根據(jù)其權(quán)限的不同在子類(lèi)中的訪問(wèn)權(quán)限也不同,從表3.1中可以看出超類(lèi)中定義的private成員在子類(lèi)定義的方法成員中是不可訪問(wèn)的,當(dāng)超類(lèi)、子類(lèi)在同一個(gè)包中時(shí),超類(lèi)的public、protected、friendly成員可以在子類(lèi)中訪問(wèn)。如果從其他包內(nèi)的類(lèi)派生出子類(lèi),則在子類(lèi)中可以訪問(wèn)超類(lèi)中的protected和public成員。子類(lèi)在定義新的成員時(shí),允許新成員與超類(lèi)成員同名。對(duì)于同名變量成員,超類(lèi)中的相應(yīng)成員被隱藏。對(duì)于同名方法成員,如果參數(shù)形式相同且返回值類(lèi)型相同,則超類(lèi)中的該方法成員被隱藏;如果參數(shù)形式不同,則調(diào)用時(shí)根據(jù)實(shí)參類(lèi)型決定調(diào)用哪一個(gè)方法成員,與類(lèi)內(nèi)方法重載相同(見(jiàn)3.6.1節(jié))。Java語(yǔ)言不允許子類(lèi)與超類(lèi)方法同名且參數(shù)形式相同但返回值類(lèi)型不同。3.5.2super
如果程序中需要訪問(wèn)被隱藏的同名超類(lèi)成員,可以使用關(guān)鍵字super,super指代當(dāng)前對(duì)象在超類(lèi)中定義的那一部分。程序3.8和3.9分別演示了如何訪問(wèn)超類(lèi)中的同名變量成員和方法成員。
【程序3.8】
用super訪問(wèn)超類(lèi)同名變量成員。
classTest{
inti;
publicTest(){i=10;}
}
publicclassTest1extendsTest{
doublei;
publicTest1(){i=12.345678;}
publicvoidprint()
{
System.out.println("iofsubclass"+i); //訪問(wèn)子類(lèi)成員i
System.out.println("iofsuperclass"+super.i); //訪問(wèn)超類(lèi)成員i
} publicstaticvoidmain(String[]args)
{
Test1t1=newTest1();
t1.print();
}
}
【程序3.9】用super訪問(wèn)超類(lèi)同名方法成員。
classTest{
inti;
publicTest(){i=10;}
publicvoidprint() {
System.out.println("iofsuperclass"+i);
}
}
publicclassTest1extendsTest
{
doublei;
publicTest1(){i=12.345678;}
publicvoidprint()
{
System.out.println("iofsubclass"+i); super.print(); //訪問(wèn)超類(lèi)中定義的print方法
}
publicstaticvoidmain(String[]args)
{
Test1t1=newTest1();
t1.print();
}
}3.5.3子類(lèi)對(duì)象的構(gòu)造
子類(lèi)對(duì)象在創(chuàng)建時(shí)需要調(diào)用超類(lèi)的構(gòu)造方法來(lái)構(gòu)造超類(lèi)中定義的那部分成員,如果在子類(lèi)中不特別聲明,則調(diào)用超類(lèi)不帶參數(shù)的構(gòu)造方法。
如果超類(lèi)沒(méi)有不帶參數(shù)的構(gòu)造方法,必須在子類(lèi)的構(gòu)造方法中用super關(guān)鍵字指定如何調(diào)用超類(lèi)的構(gòu)造方法。先看下面的程序:
classA{
inta;
A(inta){ this.a=a;
}
}
classBextendsA{
intb;
B(intb){
this.b=b;
System.out.println("ClassB");
}
}
publicclassClass1
{
publicstaticvoidmain(String[]args)
{
Bb=newB(10);
}
}
該程序中類(lèi)A構(gòu)造方法帶有一個(gè)int類(lèi)型的參數(shù),類(lèi)B為類(lèi)A的子類(lèi)。使用VisualJ++編譯該程序,給出如下的錯(cuò)誤信息:
Class'A'doesn'thaveaconstructorthatmatches'A()'這個(gè)錯(cuò)誤信息表明,在構(gòu)造類(lèi)B對(duì)象時(shí)試圖調(diào)用類(lèi)A不帶參數(shù)的構(gòu)造方法。程序3.10演示了如何使用super關(guān)鍵字調(diào)用超類(lèi)的構(gòu)造方法。
【程序3.10】super關(guān)鍵字的使用。
classPoint{
privateintx=0,y=0;
publicPoint(intx,inty){setX(x);setY(y);}
publicPoint(){this(0,0);
publicintgetX(){returnx;}
publicvoidsetX(intx){this.x=x;} publicintgetY(){returny;}
publicvoidsetY(inty){this.y=y;}
}
classColorPointextendsPoint{ //從Point派生出ColorPoint
privateintcolor=0; //增加新的變量
publicColorPoint(intx,inty,intcolor)
{
super(x,y); //訪問(wèn)超類(lèi)構(gòu)造方法,如無(wú)此句,則創(chuàng)建ColorPoint //對(duì)象時(shí)訪問(wèn)超類(lèi)中不帶參數(shù)的構(gòu)造方法
setColor(color);
}
publicintgetColor(){returncolor;}
publicvoidsetColor(intcolor){this.color=color;}
}3.5.4final方法與final類(lèi)
通過(guò)在子類(lèi)中定義與超類(lèi)同名的方法成員,覆蓋超類(lèi)的方法成員,改變了超類(lèi)原有的特征。有時(shí)可能程序員不希望子類(lèi)修改超類(lèi)原有的特性,這時(shí)可以將對(duì)應(yīng)的方法定義為最終(final)方法,子類(lèi)不再可以覆蓋該方法。例如:
classA{
finalvoidMethod1(){System.out.println(“Thisisafinalmethod”);}
}
當(dāng)從類(lèi)A派生子類(lèi)時(shí),子類(lèi)不可以定義與Method1形式相同的方法。關(guān)鍵字final也可以用來(lái)修飾類(lèi)的定義,將一個(gè)類(lèi)定義為最終類(lèi),則不再可以從該類(lèi)派生出子類(lèi)。基本語(yǔ)法形式為
finalclass類(lèi)名{
… //成員定義
}
3.5.5改進(jìn)的案例
從程序3.5案例的初步實(shí)現(xiàn)可以看出,SalaryEmployee、HourlyEmployee和CommisionEmployee三個(gè)類(lèi)有不同的特性,也有相同的特性,可以將這些相同的特性提取出來(lái)定義一個(gè)超類(lèi)Employee。程序3.11給出了改進(jìn)后的實(shí)現(xiàn)?!境绦?.11】本章案例的改進(jìn)實(shí)現(xiàn)。
//Employee.java
publicclassEmployee{
publicEmployee(Stringname){
setName(name);
}
publicdoubleCalculateSalary(){
return0.0;
}
publicvoidPrintSalary(){
System.out.println(getName()+"\t"+CalculateSalary());}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
=name;
}
Stringname;
}//SalaryEmployee.java
publicclassSalaryEmployeeextendsEmployee{
privatedoublesalary;
publicSalaryEmployee(Stringname,doublesalary){
super(name);
this.setSalary(salary);
}
publicdoubleCalculateSalary(){
returngetSalary();
}
publicdoublegetSalary(){returnsalary;
}
publicvoidsetSalary(doublesalary){
this.salary=salary;
}
}
//HourlyEmployee.java
publicclassHourlyEmployeeextendsEmployee{
publicHourlyEmployee(Stringname,doublehours,doublewage){
super(name);this.setHours(hours);
this.setWage(wage);
}
privatedoublehours; //小時(shí)數(shù)
privatedoublewage; //每小時(shí)工資額
publicdoubleCalculateSalary(){
returngetHours()*getWage();
}
publicdoublegetHours(){
returnhours;
}publicvoidsetHours(doublehours){
this.hours=hours;
}
publicdoublegetWage(){
returnwage;
}
publicvoidsetWage(doublewage){
this.wage=wage;
}
}
//CommisionEmployee.javapublicclassCommisionEmployeeextendsEmployee{
publicCommisionEmployee(Stringname,doublerate,doublesales){
super(name);
this.setRate(rate);
this.setSales(sales);
}
privatedoublerate;
privatedoublesales;
publicdoubleCalculateSalary(){returngetRate()*getSales();
}
publicdoublegetRate(){
returnrate;
}
publicvoidsetRate(doublerate){
this.rate=rate;
}
publicdoublegetSales(){
returnsales;}
publicvoidsetSales(doublesales){
this.sales=sales;
}
}
//Main.java
importjava.util.Scanner;
publicclassMain{
publicstaticvoidmain(String[]args){
//TODOcodeapplicationlogichereScannerinput=newScanner(System.in);
Stringname;
EmployeeaEmployee;
System.out.println("請(qǐng)輸入員工類(lèi)別:1.固定工資員工2.小時(shí)工3.傭金員工");
intchoice=input.nextInt();
input.nextLine();
switch(choice)
{case1:
System.out.println("輸入員工的姓名,工資額:");
name=input.nextLine();
doublesalary=input.nextDouble();
aEmpl
溫馨提示
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025版實(shí)習(xí)生實(shí)習(xí)期間實(shí)習(xí)單位培訓(xùn)責(zé)任協(xié)議3篇
- 寫(xiě)字樓電梯管理協(xié)議
- 2025個(gè)人貨車(chē)租賃合同書(shū)
- 建筑工程:車(chē)庫(kù)雨棚施工合同范本
- 家政服務(wù)伸縮縫安裝施工協(xié)議
- 2025版勞動(dòng)合同補(bǔ)充協(xié)議范本匯編3篇
- 2024年教育培訓(xùn)機(jī)構(gòu)廣告合作合同范本3篇
- 自建房屋建筑設(shè)備租賃合同
- 證券投資聯(lián)合體投標(biāo)協(xié)議模板
- 2025年度爬架租賃及拆除服務(wù)合同3篇
- 學(xué)生宿舍消防安全制度模版(3篇)
- 四川省成都市2023-2024學(xué)年高二上學(xué)期期末調(diào)研考試語(yǔ)文試題(解析版)
- 《兩用物項(xiàng)證》課件
- 《電梯維保規(guī)則》課件
- DB54T 0425.1-2024 公共數(shù)據(jù) 數(shù)據(jù)元規(guī)范 第一部分:總則
- 江蘇省泰州市2023-2024學(xué)年高一上學(xué)期期末語(yǔ)文試題及答案
- 2024年高考政治選必二《法律與生活》重要知識(shí)問(wèn)題梳理總結(jié)
- 孕早期nt檢查課件
- 【MOOC】工程制圖解讀-西安交通大學(xué) 中國(guó)大學(xué)慕課MOOC答案
- 期末復(fù)習(xí)(試題)-2024-2025學(xué)年三年級(jí)上冊(cè)數(shù)學(xué)蘇教版
- 檢驗(yàn)科新進(jìn)人員崗前培訓(xùn)
評(píng)論
0/150
提交評(píng)論