《Java程序設(shè)計(jì)》課件第3章_第1頁(yè)
《Java程序設(shè)計(jì)》課件第3章_第2頁(yè)
《Java程序設(shè)計(jì)》課件第3章_第3頁(yè)
《Java程序設(shè)計(jì)》課件第3章_第4頁(yè)
《Java程序設(shè)計(jì)》課件第3章_第5頁(yè)
已閱讀5頁(yè),還剩285頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(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ì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論