Java中類(lèi)、對(duì)象、接口及包的概念課件_第1頁(yè)
Java中類(lèi)、對(duì)象、接口及包的概念課件_第2頁(yè)
Java中類(lèi)、對(duì)象、接口及包的概念課件_第3頁(yè)
Java中類(lèi)、對(duì)象、接口及包的概念課件_第4頁(yè)
Java中類(lèi)、對(duì)象、接口及包的概念課件_第5頁(yè)
已閱讀5頁(yè),還剩120頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

Java中類(lèi)、對(duì)象、介面及

包的概念6.1類(lèi)的基本概念

傳統(tǒng)的過(guò)程式語(yǔ)言,如C,由於它的設(shè)計(jì)方式與客觀世界之間存在差距,使得程式的編寫(xiě)首先必須定義所要實(shí)現(xiàn)的功能,然後確定需採(cǎi)取的步驟,即所謂的“逐步求精”的結(jié)構(gòu)程式設(shè)計(jì)方法。實(shí)際開(kāi)發(fā)中,當(dāng)程式大到一定程度的時(shí)候,其調(diào)試和維護(hù)就變得很困難,使用過(guò)程式語(yǔ)言就會(huì)感到力不從心了。

前面我們說(shuō)過(guò),Java是一種純面向?qū)ο蟮木幊陶Z(yǔ)言,而面向?qū)ο蟪淌皆O(shè)計(jì)是近些年來(lái)才發(fā)展起來(lái)的程式設(shè)計(jì)方法,其基本思想是將現(xiàn)實(shí)世界中的事物抽象為對(duì)象,抽象出來(lái)的對(duì)象被賦給相應(yīng)的狀態(tài)和行為,通過(guò)對(duì)消息的回應(yīng)完成一定的任務(wù)。在現(xiàn)實(shí)生活中,任何事物都可以被認(rèn)為是對(duì)象(Object),如:

①電梯

②街頭的自動(dòng)售貨機(jī)

③街上跑的汽車(chē)

④凳子

⑤人

……

上面列舉的對(duì)象都有兩個(gè)共性:

(1)具有一定的狀態(tài)和特性。比如汽車(chē)有輪胎、發(fā)動(dòng)機(jī)、方向盤(pán)等。

(2)每個(gè)對(duì)象對(duì)應(yīng)一組特定的操作。比如汽車(chē)需保養(yǎng)、加油、清洗等。面向?qū)ο蟪淌皆O(shè)計(jì)方法就是把現(xiàn)實(shí)世界中對(duì)象的狀態(tài)和操作抽象為程式設(shè)計(jì)語(yǔ)言中的對(duì)象,達(dá)到二者的統(tǒng)一。同一種對(duì)象的所有共性進(jìn)行抽象,又得到了類(lèi)的概念。

所以,面向?qū)ο蟪淌皆O(shè)計(jì)中的對(duì)象是由描述狀態(tài)的變數(shù)和對(duì)這些變數(shù)進(jìn)行維護(hù)和操作的一系列方法組成的事務(wù)處理單位,而類(lèi)相當(dāng)於創(chuàng)建對(duì)象實(shí)例的範(fàn)本,通過(guò)對(duì)其實(shí)例化得到同一類(lèi)的不同實(shí)例。本章我們將討論類(lèi)的特性、成員變數(shù),方法、對(duì)象的建立及初始化、對(duì)象的繼承及介面與包等內(nèi)容。

類(lèi)是對(duì)一個(gè)或幾個(gè)相似對(duì)象的描述,它把不同對(duì)象具有的共性抽象出來(lái),定義某類(lèi)對(duì)象共有的變數(shù)和方法,從而使程式員實(shí)現(xiàn)代碼的複用,所以說(shuō),類(lèi)是同一類(lèi)對(duì)象的原型。創(chuàng)建一個(gè)類(lèi),相當(dāng)於構(gòu)造一個(gè)新的數(shù)據(jù)類(lèi)型,而實(shí)例化一個(gè)類(lèi)就得到一個(gè)對(duì)象。Java為我們提供了大量的類(lèi)庫(kù),如果從已知類(lèi)庫(kù)入手來(lái)構(gòu)造自己的程式,不僅能有效地簡(jiǎn)化程式設(shè)計(jì),而且能很好地學(xué)習(xí)面向?qū)ο蟪淌皆O(shè)計(jì)方法。其實(shí),前面很多例子已經(jīng)對(duì)類(lèi)的組成有了明確地說(shuō)明,一個(gè)類(lèi)的實(shí)現(xiàn)包含兩部分內(nèi)容:聲明和實(shí)體。類(lèi)的各部分組成如圖6.1所示。圖6.16.1.1類(lèi)的聲明類(lèi)聲明包括關(guān)鍵字class、類(lèi)名及類(lèi)的屬性。類(lèi)名必須是合法的識(shí)別字,類(lèi)的屬性為一些可選的關(guān)鍵字。其聲明格式如下:

[public|private|friendly|protected][abstract][final]classclassName

[extendssuperclassName][implementsinterfaceNameList] {...}

其中,第一項(xiàng)屬於訪問(wèn)控制符,它不僅針對(duì)於類(lèi),類(lèi)的變數(shù)、方法的訪問(wèn)也有該項(xiàng)的限制,我們後面會(huì)做專(zhuān)門(mén)的介紹。其他的修飾符說(shuō)明如下:●abstract:聲明該類(lèi)不能被實(shí)例化?!駀inal:聲明該類(lèi)不能被繼承,即沒(méi)有子類(lèi)?!馽lassclassName:關(guān)鍵字class告訴編譯器表示類(lèi)的聲明以及類(lèi)名是className?!馿xtendssuperclassName:extends語(yǔ)句擴(kuò)展superclassName為該類(lèi)的父類(lèi)?!駃mplementsinterfaceNameList:聲明類(lèi)可實(shí)現(xiàn)一個(gè)或多個(gè)介面,可以使用關(guān)鍵字implements並且在其後面給出由類(lèi)實(shí)現(xiàn)的多個(gè)介面名字列表,各介面之間以逗號(hào)分隔。如圖6.1中的

publicclassstack {...}

即為類(lèi)的聲明。6.1.2類(lèi)的實(shí)體類(lèi)體是類(lèi)的主要部分,包括變數(shù)的說(shuō)明及該類(lèi)所支持的方法,我們習(xí)慣稱(chēng)之為成員變數(shù)和成員方法。需要注意的是,除了類(lèi)體中定義的變數(shù)與方法外,該類(lèi)還繼承了其父類(lèi)的變數(shù)與方法。當(dāng)然,對(duì)父類(lèi)變數(shù)和方法的訪問(wèn)要受到訪問(wèn)控制條件的限制。類(lèi)體說(shuō)明的格式為

classclassName{

variableDeclaration methodDeclaration }

讀者可參照?qǐng)D6.1仔細(xì)體會(huì)類(lèi)體所包含的內(nèi)容。

1.變數(shù)

Java中變數(shù)的說(shuō)明可以分為兩種:類(lèi)成員變數(shù)的說(shuō)明和方法變數(shù)的說(shuō)明。其變數(shù)聲明格式為

[public|protected|private][static][final][transient][volatile] typevariableName

上述聲明格式中,第一項(xiàng)指的是訪問(wèn)控制格式(我們後面會(huì)有介紹),另外的幾項(xiàng)我們說(shuō)明如下:●static:成員控制修飾符,說(shuō)明該類(lèi)型的變數(shù)為靜態(tài)變數(shù),或者稱(chēng)之為類(lèi)變數(shù)。說(shuō)明靜態(tài)變數(shù)類(lèi)型後則該類(lèi)的所有實(shí)例對(duì)象都可以對(duì)其共用,而且訪問(wèn)靜態(tài)變數(shù)無(wú)須事先初始化它所在的類(lèi)?!駀inal:常量聲明修飾符,與C/C++類(lèi)似,用該符號(hào)聲明後,在程式的運(yùn)行過(guò)程中不能再改變它的值。實(shí)際使用中,final往往與static結(jié)合在一起使用。比如:

finalintINDEX=1000;staticfinalintLOOP=10;●volatile:非同步控制修飾符,表示多個(gè)併發(fā)線程共用的變數(shù),這使得各線程對(duì)該變數(shù)的訪問(wèn)保持一致?!駎ransient:存儲(chǔ)控制臨時(shí)變數(shù)修飾符,因?yàn)樵谌笔〉那闆r下,類(lèi)中所有變數(shù)都是對(duì)象永久狀態(tài)的一部分,將對(duì)象存檔時(shí),必須同時(shí)保存這些變數(shù)。用該限定詞修飾的變數(shù)指示Java虛擬機(jī):該變數(shù)並不屬於對(duì)象的永久狀態(tài)。它主要用於實(shí)現(xiàn)不同對(duì)象的存檔功能??傊瑥淖償?shù)定義的不同位置及所使用的限定詞不同來(lái)看,變數(shù)可以分為三類(lèi):實(shí)例變數(shù)、局部變數(shù)和靜態(tài)變數(shù)。

如果在類(lèi)的方法代碼段之外聲明且沒(méi)有限定詞static,則為實(shí)例變數(shù)。從它的定義我們可以看出,實(shí)例變數(shù)與類(lèi)緊密相關(guān),如果一個(gè)類(lèi)有多個(gè)實(shí)例對(duì)象,那麼每個(gè)實(shí)例對(duì)象都有自己的實(shí)例變數(shù)拷貝,之間並不影響。

如果在類(lèi)的方法本體之中聲明,則為局部變數(shù),這有點(diǎn)與C語(yǔ)言函數(shù)中定義的局部變數(shù)相似。由於局部變數(shù)是在方法體內(nèi)所定義,因而只能在本方法中使用,無(wú)所謂訪問(wèn)控制,也不能用static修飾符加以說(shuō)明。另外,需要注意的是局部變數(shù)使用前必須初始化,這也是它與實(shí)例變數(shù)及後面要介紹的靜態(tài)變數(shù)之間的不同之處。局部變數(shù)可以與實(shí)例變數(shù)同名而相互不影響。如果將一個(gè)實(shí)例變數(shù)聲明為static,則為靜態(tài)變數(shù),或稱(chēng)之為類(lèi)變數(shù)。靜態(tài)變數(shù)在類(lèi)聲明後就可以直接引用,但實(shí)例變數(shù)則不能,必須在實(shí)例化對(duì)象後才可以使用。

下麵我們對(duì)實(shí)例變數(shù)與類(lèi)變數(shù)加以詳細(xì)地說(shuō)明,以加深讀者的理解。比如我們可以如下來(lái)聲明一個(gè)成員變數(shù):

classMyClass{publicfloatvariable1;publicstaticintvariable2}

該例中聲明了一個(gè)實(shí)例變數(shù)variable1和一個(gè)類(lèi)變數(shù)variable2。今後當(dāng)我們創(chuàng)建類(lèi)的實(shí)例的時(shí)候,系統(tǒng)就會(huì)為該實(shí)例創(chuàng)建一個(gè)類(lèi)實(shí)例的副本,但系統(tǒng)為每個(gè)類(lèi)分配類(lèi)變數(shù)僅僅只有一次,而不管類(lèi)創(chuàng)建的實(shí)例有多少。當(dāng)?shù)谝淮握{(diào)用類(lèi)的時(shí)候,系統(tǒng)為類(lèi)變數(shù)分配記憶體。所有的實(shí)例共用了類(lèi)的類(lèi)變數(shù)的相同副本。在程式中可通過(guò)一個(gè)實(shí)例或者類(lèi)本身來(lái)訪問(wèn)類(lèi)變數(shù)。例如:

MyClassA=newMyClass();

MyClassB=newMyClass();A.variable1=100;A.variable2=200;B.variable1=300;B.variable2=400; System.out.println("A.variable1="+A.variable1); System.out.println("A.variable2="+A.variable2); System.out.println("A.variable1="+A.variable1); System.out.println("A.variable1="+A.variable1);...

當(dāng)我們從類(lèi)實(shí)例化新對(duì)象的時(shí)候,就得到了類(lèi)實(shí)例變數(shù)的一個(gè)新副本。這些副本跟新對(duì)象是聯(lián)繫在一起的。因此,每實(shí)例化一個(gè)新MyClass對(duì)象的時(shí)候,就得到了一個(gè)和MyClass對(duì)象有聯(lián)繫的variable1的新副本。當(dāng)一個(gè)成員變數(shù)用關(guān)鍵字static被指定為類(lèi)變數(shù)後,其第一次調(diào)用的時(shí)候,系統(tǒng)就會(huì)為它創(chuàng)建一個(gè)副本,之後,類(lèi)的所有實(shí)例均共用了該類(lèi)變數(shù)的相同副本。所以上述程式段的輸出結(jié)果為

A.variable1=100A.variable2=400B.variable1=300B.variable2=4002.方法

Java程式通過(guò)方法完成對(duì)類(lèi)和對(duì)象屬性的操作。方法定義了在類(lèi)成員變數(shù)上的一系列操作,它只能在類(lèi)的內(nèi)部聲明並加以實(shí)現(xiàn),其他的對(duì)象通過(guò)調(diào)用對(duì)象的方法得到該對(duì)象的服務(wù)。方法的定義包含兩部分內(nèi)容:方法聲明和方法體。1)方法聲明方法聲明的一般格式如下:

[public/protected/private][static][final][abstract][native][synchronized]

returnTypemethodName([paramList])[throwsexceptionList] {...}

在方法聲明中應(yīng)包括方法名、方法的返回值類(lèi)型、方法的修飾詞、參數(shù)的數(shù)目和類(lèi)型及方法可能產(chǎn)生的例外。從其聲明格式中可以發(fā)現(xiàn),不一定要全部顯示並指明所有的資訊,方法最基本的聲明格式為

returnTypemethodName()

{...}

一般聲明格式中的第一項(xiàng)是訪問(wèn)控制屬性,後面會(huì)介紹。其他幾個(gè)修飾詞我們說(shuō)明如下:●static:說(shuō)明該方法為靜態(tài)方法。與變數(shù)的定義類(lèi)似,靜態(tài)方法我們也稱(chēng)作類(lèi)方法,與之對(duì)應(yīng),其他的方法就為實(shí)例方法。靜態(tài)方法屬於類(lèi),所以只要對(duì)類(lèi)作了聲明,就可以調(diào)用該類(lèi)的類(lèi)方法,即使用時(shí)無(wú)須類(lèi)的初始化。當(dāng)然,實(shí)例方法只能在類(lèi)的實(shí)例或子類(lèi)的實(shí)例中調(diào)用。類(lèi)方法只能操作類(lèi)變數(shù)而不能訪問(wèn)定義在類(lèi)中的實(shí)例變數(shù),這是實(shí)際使用過(guò)程中經(jīng)常出錯(cuò)的地方。例如:classA{intx;staticpublicintx(){returnx;}staticpublicvoidsetX(intnewX){x=newX;}}...AmyX=newA();AanotherX=newA();myX.setX(1);anotherX.x=2;System.out.println("myX.x="+myX.x());System.out.println("anotherX.x="+anotherX.x());...當(dāng)我們編譯的時(shí)候,編譯器會(huì)給出以下的錯(cuò)誤資訊:A.java:4:Can'tmakeastaticreferencetononstaticvariablexinclassA.returnx;^出現(xiàn)這個(gè)錯(cuò)誤的原因是類(lèi)方法不能訪問(wèn)實(shí)例變數(shù),如果把類(lèi)的定義改為classAnIntegerNamedX{staticintx;staticpublicintx(){returnx;}staticpublicvoidsetX(intnewX){x=newX;}}類(lèi)就可以成功編譯了:myX.x=2anotherX.x=2實(shí)例成員和類(lèi)成員之間的另外不同點(diǎn)是類(lèi)成員可以在類(lèi)本身中訪問(wèn),而不必實(shí)例化一個(gè)類(lèi)來(lái)訪問(wèn)類(lèi)成員。

下麵再對(duì)上面的代碼進(jìn)行修改:

...A.setX(1);System.out.println("A.x="+A.x());...

這裏我們不用實(shí)例化類(lèi)對(duì)象myX和anotherX就可以直接從類(lèi)A中設(shè)置x並輸出x。這樣同樣可以得到類(lèi)變數(shù)x的值?!馻bstract:說(shuō)明一個(gè)方法是抽象方法,即該方法只有方法說(shuō)明而沒(méi)有方法體。抽象方法的實(shí)現(xiàn)須由該方法所在類(lèi)的子類(lèi)來(lái)實(shí)現(xiàn)。如果一個(gè)類(lèi)包含一個(gè)或多個(gè)抽象方法,則該類(lèi)必須為抽象類(lèi)。抽象類(lèi)不能被實(shí)例化。例如:

classShape{ abstractvoiddraw();}

該例中的說(shuō)明方法draw()為抽象方法。●final:final方法類(lèi)似於常量的定義,它說(shuō)明一個(gè)方法為終極方法,即它不能被子類(lèi)重載。說(shuō)明為final的方法往往與關(guān)鍵字private一起使用,避免出錯(cuò)。例如:

...privatefinalmeth_final(){...}●native、synchronized:程式中native指明本方法是用與平臺(tái)有關(guān)的開(kāi)發(fā)語(yǔ)言編寫(xiě)的,也就是說(shuō)用來(lái)把Java代碼和其他語(yǔ)言的代碼集成在一起。synchronized主要用於多線程程式設(shè)計(jì),說(shuō)明某一方法是同步方法,用來(lái)控制多個(gè)併發(fā)線程對(duì)共用數(shù)據(jù)的訪問(wèn)。我們後面在講線程的時(shí)候還要作介紹。2)方法重載

Java中方法的重載指的是多個(gè)方法共用一個(gè)名字(這樣可實(shí)現(xiàn)對(duì)象的多態(tài)),同時(shí),不同的方法要麼參數(shù)個(gè)數(shù)各不相同,或者是參數(shù)類(lèi)型不同。Java提供的標(biāo)準(zhǔn)類(lèi)中包含了許多構(gòu)造函數(shù),並且每個(gè)構(gòu)造函數(shù)允許調(diào)用者為新對(duì)象的不同實(shí)例變數(shù)提供不同的初始數(shù)值。比如,java.awt.Rectangle就有三個(gè)構(gòu)造函數(shù):

Rectangle(){};Rectangle(intwidth,intheight){};Rectangle(intx,inty,intwidth,intheight){};

當(dāng)我們傳遞不同的參數(shù)時(shí),構(gòu)造出來(lái)的對(duì)象的實(shí)例具有不同的屬性。3)方法中參數(shù)的使用在方法的聲明格式中,需要指明返回值的類(lèi)型。當(dāng)一個(gè)方法不需要返回值的時(shí)候,其類(lèi)型說(shuō)明為void,否則方法體中必須包含return語(yǔ)句。返回值既可以是基本數(shù)據(jù)類(lèi)型,也可以是複雜數(shù)據(jù)類(lèi)型。在C語(yǔ)言、PASCAL語(yǔ)言中,函數(shù)、過(guò)程的參數(shù)都存在值傳遞/參數(shù)傳遞的問(wèn)題。比如C語(yǔ)言中如果參數(shù)是指針或數(shù)組名則為參數(shù)傳遞。我們知道,Java中由於取消了指針,不可能像C一樣直接操作記憶體,但是由於對(duì)象的動(dòng)態(tài)聯(lián)編性,複雜數(shù)據(jù)類(lèi)型作參數(shù)相當(dāng)於指針的使用,即參數(shù)傳遞,而基本數(shù)據(jù)類(lèi)型作參數(shù)傳遞則相當(dāng)於值傳遞。比如下例:例6.1

classswapByValue{ intx,y; publicswapByValue(intx,inty) { this.x=x; this.y=y; } publicvoidswap(intx,inty) {intz; z=x;x=y;y=z;} publicstaticvoidmain(Stringargs[]){swapByValues=newswapByValue(3,4); Transcript.println("Beforeswap:x="+s.x+"y="+s.y);s.swap(s.x,s.y); Transcript.println("Afterswap:x="+s.x+"y="+s.y);} }運(yùn)行結(jié)果如圖6.2所示。圖6.2例6.2

classswapByAddress{ intx,y; publicswapByAddress(intx,inty) { this.x=x; this.y=y; } publicvoidswap(Integerx,Integery) {Integerz; z=x;x=y;y=z; this.x=x.intValue(); this.y=y.intValue(); }publicstaticvoidmain(Stringargs[]){ swapByAddresss=newswapByAddress(3,4); Transcript.println("Beforeswap:x="+s.x+"y="+s.y); s.swap(newInteger(s.x),newInteger(s.y)); Transcript.println("Afterswap:x="+s.x+"y="+s.y); }}運(yùn)行後的結(jié)果如圖6.3所示。圖6.3

在例6.1和例6.2中均出現(xiàn)了一個(gè)關(guān)鍵字this,它起什麼作用呢?Java中關(guān)鍵字this表示當(dāng)前對(duì)象。因?yàn)閷?shí)際程式編寫(xiě)過(guò)程中,可能會(huì)出現(xiàn)局部變數(shù)名和成員變數(shù)名同名,如例6.3中有:

classswapByAddress{ intx,y; public

swapByAddress(intx,inty) { this.x=x; this.y=y; }

其中,對(duì)象swapByAdress中定義了兩個(gè)成員變數(shù)x、y,同時(shí)方法swapByAddress中也出現(xiàn)了以x、y命名的局部變數(shù),為了避免由此可能造成的二義性,程式中我們用this關(guān)鍵字作首碼修飾詞來(lái)指明是當(dāng)前對(duì)象的實(shí)例變數(shù)。與此類(lèi)似,用this關(guān)鍵字同樣可以調(diào)用當(dāng)前對(duì)象的某個(gè)方法。4)構(gòu)造方法構(gòu)造方法用來(lái)初始化新創(chuàng)建的對(duì)象。類(lèi)可以包含一個(gè)或者多個(gè)構(gòu)造方法,不同的構(gòu)造方法根據(jù)參數(shù)的不同來(lái)決定要初始化的新對(duì)象的狀態(tài)。所有的Java類(lèi)都有構(gòu)造方法,它用來(lái)對(duì)新的對(duì)象進(jìn)行初始化。構(gòu)造方法與類(lèi)的名字是相同的。比如,Stack類(lèi)的構(gòu)造方法的名字為Stack,而Rectangle類(lèi)的構(gòu)造方法的名字為Rectangle,Thread類(lèi)的構(gòu)造方法的名字為T(mén)hread。下麵給出Stack類(lèi)的構(gòu)造方法:publicStack(){items=newVector(10);}Java支持對(duì)構(gòu)造方法的重載,這樣一個(gè)類(lèi)就可以有多個(gè)構(gòu)造方法,所有的構(gòu)造方法的名字都是相同的,只是所帶參數(shù)的個(gè)數(shù)和類(lèi)型相異而已。下麵是類(lèi)Stack的另一個(gè)構(gòu)造方法。這個(gè)構(gòu)造方法是根據(jù)它的參數(shù)來(lái)初始化堆疊的大小。

publicStack(intinitialSize){items=newVector(initialSize);}

從上面可以看出,兩個(gè)構(gòu)造方法都有相同的名字,但是它們有不同的參數(shù)列表。編譯器會(huì)根據(jù)參數(shù)列表的數(shù)目以及類(lèi)型來(lái)區(qū)分這些構(gòu)造方法。所以,當(dāng)創(chuàng)建對(duì)象的時(shí)候,要根據(jù)它的參數(shù)是否與初始化的新對(duì)象相匹配來(lái)選擇構(gòu)造方法。根據(jù)傳遞給構(gòu)造方法參數(shù)的數(shù)目和類(lèi)型,編譯器可以決定要使用哪個(gè)構(gòu)造方法。如對(duì)於下麵的代碼,編譯器就可以知道應(yīng)該是使用單一的整型參數(shù)來(lái)初始化對(duì)象:

newStack(10);

與此相同,當(dāng)我們給出下麵代碼的時(shí)候,編譯器選擇沒(méi)有參數(shù)的構(gòu)造方法或者缺省的構(gòu)造方法進(jìn)行初始化:

newStack();

另外,如果生成的類(lèi)不為它提供構(gòu)造方法,系統(tǒng)會(huì)自動(dòng)提供缺省的構(gòu)造方法。這個(gè)缺省的構(gòu)造方法不會(huì)完成任何事情。下例給出類(lèi)AnimationThread的構(gòu)造方法,在其初始化過(guò)程中設(shè)置了一些缺省的數(shù)值,比如幀速度、圖片的數(shù)目等。classAnimationThreadextendsThread{intframesPerSecond;

intnumImages;Image[]images;AnimationThread(intfps,intnum){super("AnimationThread");this.framesPerSecond=fps;this.numImages=num;this.images=newImage[numImages];for(inti=0;i<=numImages;i++){...}}...}

從該例來(lái)看,構(gòu)造方法的實(shí)體跟一般方法的實(shí)體是相似的,均包含局部變數(shù)聲明、迴圈以及其他的語(yǔ)句。該例的構(gòu)造方法中出現(xiàn)了以下一條語(yǔ)句:

super("AnimationThread");

與關(guān)鍵字this相似(我們知道,this表示當(dāng)前對(duì)象),關(guān)鍵字super表示當(dāng)前對(duì)象的父對(duì)象,所以使用super可以引用父類(lèi)被隱藏的變數(shù)和方法。本例中調(diào)用了父類(lèi)Thread的構(gòu)造方法。使用中我們須注意的是,父類(lèi)的構(gòu)造方法必須是子類(lèi)構(gòu)造方法的第一條語(yǔ)句,因?yàn)閷?duì)象必須首先執(zhí)行高層次的初始化。構(gòu)造方法說(shuō)明中只能帶訪問(wèn)控制修飾符,即只能使用public、protected及private中的任一個(gè)。關(guān)於訪問(wèn)控制符,後面我們會(huì)介紹。5)方法finalizefinalize在Java程式中相當(dāng)於C++中的析構(gòu)方法,它在對(duì)象退出的時(shí)候釋放掉佔(zhàn)用的資源。其聲明格式如下:

protectedvoidfinalize(){...}

有些面向?qū)ο笳Z(yǔ)言需要保持對(duì)所有對(duì)象的跟蹤,所以在對(duì)象不再使用的時(shí)候要將它從記憶體中清除,這個(gè)過(guò)程就是所謂的"垃圾收集"。

當(dāng)對(duì)象不再有引用的時(shí)候,對(duì)象就需被清除,即作為垃圾收集的對(duì)象。保留在變數(shù)中的引用通常在變數(shù)超出作用域的時(shí)候被清除,比如當(dāng)我們從某個(gè)方法調(diào)用中退出時(shí),其局部變數(shù)就自動(dòng)被清除。當(dāng)然也可以通過(guò)設(shè)置變數(shù)為null來(lái)清除對(duì)象引用。需注意的是,程式中同一個(gè)對(duì)象可以有多個(gè)引用,對(duì)象的所有引用必須在對(duì)象被垃圾收集器清除之前清除。Java有一個(gè)立即垃圾收集器,它週期性地把不再被引用的對(duì)象從記憶體中清除。這個(gè)垃圾收集器是自動(dòng)執(zhí)行的,我們也可以通過(guò)調(diào)用系統(tǒng)類(lèi)的System.gc()方法來(lái)顯式地運(yùn)行垃圾收集程式(比如在創(chuàng)建大量垃圾代碼之後或者在需要大量記憶體代碼之前運(yùn)行垃圾收集器)。在一個(gè)對(duì)象被系統(tǒng)垃圾收集器處理之前,對(duì)象也可調(diào)用自己的finalize方法進(jìn)行析構(gòu)處理,這個(gè)過(guò)程就是所說(shuō)的最後處理,也有的參考資料稱(chēng)之為結(jié)束方法。

Java中構(gòu)造方法和結(jié)束方法在類(lèi)中均是可選的,尤其是結(jié)束方法在一般情況下是不需要的,而提供結(jié)束方法finalize的目的是讓程式員有機(jī)會(huì)釋放掉不能被自動(dòng)記憶體管理器直接使用的資源或是不能自動(dòng)釋放掉的資源。6)變數(shù)和方法的訪問(wèn)控制前面我們多次提到過(guò)對(duì)類(lèi)、變數(shù)及方法的訪問(wèn)控制屬性,比如有:private、friendly、protected及public。Java中最低訪問(wèn)控制範(fàn)圍是類(lèi)的級(jí)別,與之對(duì)應(yīng)也分為四種:同一個(gè)類(lèi)、同一個(gè)包、不同包的子類(lèi)及不同包的非子類(lèi)。表6.1給出了每一種訪問(wèn)指示的訪問(wèn)等級(jí)。表6.1訪問(wèn)控制權(quán)限表訪問(wèn)指示類(lèi)子類(lèi)包所有private√

protected√√√

public√√√√friendly√

表6.1中,第二列給出了是否類(lèi)本身可以訪問(wèn)它的成員(從上表可以知道,類(lèi)總是可以訪問(wèn)它自己的成員);第三列給出了是否類(lèi)的子類(lèi)可以訪問(wèn)它的成員;第四列給出了是否在相同包中的類(lèi)可以訪問(wèn)該類(lèi)成員;第五列給出了是否所有的類(lèi)可以訪問(wèn)該類(lèi)成員。類(lèi)的訪問(wèn)控制權(quán)限只能為public和friendly,變數(shù)和方法的訪問(wèn)控制可以為上面四種的任何一種?!駊rivateprivate成員只能被它所定義的類(lèi)或類(lèi)的不同對(duì)象所訪問(wèn)。外部訪問(wèn)這個(gè)變數(shù)就會(huì)出錯(cuò),因?yàn)槿绻鹥rivate的方法被外部類(lèi)調(diào)用,就會(huì)使得程式或?qū)ο筇庫(kù)恫话踩珷顟B(tài)。private成員就像不能告訴任何人的秘密,所以,任何不需要他人直接訪問(wèn)的成員都應(yīng)該定義為private類(lèi)型。下麵的類(lèi)A包含了一個(gè)private成員變數(shù)和一個(gè)private方法:classA{privateintprivateVariable;privatevoidprivateMethod(){System.out.println("Testforprivatedefinition!");}}

在做了以上的定義之後,A類(lèi)型的對(duì)象可以調(diào)用或者修改privateVariable變數(shù)以及調(diào)用privateMethod方法,但是其他類(lèi)型的對(duì)象卻不行。比如,以下的類(lèi)B就不能訪問(wèn)privateVariable變數(shù)或者調(diào)用privateMethod方法,因?yàn)轭?lèi)B不是A類(lèi)型的。

classB{voidaccessMethod(){Aa=newA();a.privateVariable=10;//非法a.privateMethod();//非法}}這時(shí),編譯器就會(huì)給出以下錯(cuò)誤資訊並拒絕繼續(xù)編譯程序:B.java:9:VariableprivateVariableinclassAnotaccessiblefromclassB.//在類(lèi)A中的privateVariable變數(shù)不能從類(lèi)B中進(jìn)行訪問(wèn)a.privateVariable=10;//非法^1error//程式中有一個(gè)錯(cuò)誤與此類(lèi)似,如果程式試圖訪問(wèn)方法privateMethod()時(shí),將導(dǎo)致如下的編譯錯(cuò)誤:B.java:12:NomethodmatchingprivateMethod()foundinclassA. //在類(lèi)A中沒(méi)有匹配的方法privateMethod()a.privateMethod(); //非法1error //一個(gè)錯(cuò)誤下麵我們?cè)俳o出一個(gè)例子來(lái)解釋同類(lèi)對(duì)象調(diào)用private的方法。假如A類(lèi)包含了一個(gè)實(shí)例方法,它用於比較當(dāng)前的A對(duì)象(this)同另外一個(gè)對(duì)象的privateVariable變數(shù)是否相等:

classA{privateintprivateVariable;

booleanisEqualTo(AanotherA){if(this.PrivateVariable==anotherA.privateVariable)returntrue;elsereturnfalse;}}

結(jié)果是運(yùn)行正常??梢?jiàn),相同類(lèi)型的對(duì)象可以訪問(wèn)其他對(duì)象的private成員。這是因?yàn)樵L問(wèn)限制只是在類(lèi)別層次(類(lèi)的所有實(shí)例)而不是在對(duì)象層次(類(lèi)的特定實(shí)例)上。

實(shí)際應(yīng)用過(guò)程中,如果我們不想讓別的類(lèi)生成自己定義的類(lèi)的實(shí)例,可以將其構(gòu)造方法聲明為private類(lèi)型。比如,java.lang.System,它的構(gòu)造方法為private,所以不能被實(shí)例化,但由於其所有方法和變數(shù)均定義為static類(lèi)型,故可以直接調(diào)用其方法和變數(shù)。●protected

定義為protected的類(lèi)成員允許類(lèi)本身、子類(lèi)以及在相同包中的類(lèi)訪問(wèn)它。一般來(lái)說(shuō),需要子類(lèi)訪問(wèn)的成員,可以使用protected進(jìn)行限制。protected成員就像家庭秘密,家裏人知道無(wú)所謂,但是卻不讓外人知道。現(xiàn)在我們看看protected是怎樣限制使用在相同包內(nèi)的類(lèi)的。假如上面的那個(gè)類(lèi)A現(xiàn)在被定義在一個(gè)包Protect1內(nèi),它有一個(gè)protected成員變數(shù)和一個(gè)protected方法,具體如下:packageProtext1;publicclassA{protectedintprotectVariable;protectedvoidprotectMethod(){System.out.println("Testforprotecteddefinition!");}}

現(xiàn)在,假設(shè)類(lèi)C也聲明為Protect1包的一個(gè)成員(不是A的子類(lèi))。則類(lèi)C可以合法地訪問(wèn)A對(duì)象的protectVariable成員變數(shù)並且可以合法調(diào)用它的protectMethod,如下:packageProtect1;classC{voidaccessMethod(){Aa=newA();a.protectVariable=10; //合法

tectMethod(); //合法

}}

下麵我們探討protected如何限制類(lèi)A子類(lèi)的訪問(wèn)。首先定義類(lèi)D,它由類(lèi)A繼承而來(lái),但處在不同的包中,設(shè)為Protect2。則類(lèi)D可以訪問(wèn)其本身類(lèi)實(shí)例成員protectVariable和protectMethod,但不能訪問(wèn)類(lèi)A對(duì)象中的protectVariable或者protectMethod。

在下面代碼中,accessMethod試圖訪問(wèn)在A類(lèi)型對(duì)象中的protectVariable成員變數(shù),這是不合法的,而訪問(wèn)D類(lèi)型對(duì)象則是合法的。與此相同,accessMethod試圖調(diào)用A對(duì)象的protectMethod方法也是非法的。見(jiàn)下例:

packageProtect2;importProtect1.*;classDextendsA{voidaccessMethod(Aa,Dd){a.protectVariable=10;//非法d.protectVariable=10;//合法

tectMethod();//非法

tectMethod();//合法

}}●publicpublic是Java中最簡(jiǎn)單的訪問(wèn)控制符。修飾為public的成員在任何類(lèi)中、任何包中都可以訪問(wèn),它相當(dāng)於是無(wú)任何秘密可言,從其使用角度來(lái)看,有點(diǎn)相當(dāng)於C語(yǔ)言中的外部變數(shù)。例如:packagePublic1;publicclassA{publicintpublicVariable;publicvoidpublicMethod(){System.out.println("Testforpublicdefinition!");}}接下來(lái),我們重新編寫(xiě)類(lèi)B,將它放置到不同的包中,並且讓它跟類(lèi)A毫無(wú)關(guān)係:packagePublic2;importPublic1.*;classB{voidaccessMethod(){Aa=newA();a.publicVariable=10;//合法

a.publicMethod();//合法

}}

從上面的代碼段我們可以看出,這時(shí)類(lèi)B可以合法地使用和修改在類(lèi)A中的publicVariable變數(shù)及方法publicMethod?!駀riendlyfriendly關(guān)鍵字我們並不陌生,在C++中其表示友元類(lèi),Java中如果不顯式設(shè)置成員訪問(wèn)控制的時(shí)候(即缺省的訪問(wèn)控制),則隱含使用friendly訪問(wèn)控制。該訪問(wèn)控制允許在相同包中的類(lèi)成員之間相互可以訪問(wèn)。就像在相同包中的類(lèi)是互相信任的朋友。下例中,類(lèi)A聲明了一個(gè)單一包訪問(wèn)的成員變數(shù)和方法。它處在Friend包中:packageFriend;classA{intfriendVariable; //缺省為friendlyvoidfriendMethod() //缺省為friendly{System.out.println("Testforfriendlydefinition!");}}這樣,所有定義在和類(lèi)A相同的包中的類(lèi)也可以訪問(wèn)friendVariable和friendMethod。

假如A和B都被定義為Friend包的一部分,則如下的代碼是合法的:

packageGreek;classB{voidaccessMethod(){Aa=newA();a.friendVariable=10; //合法

a.friendMethod(); //合法

}}6.2對(duì)象6.2.1對(duì)象的創(chuàng)建

Java中創(chuàng)建新的對(duì)象必須使用new語(yǔ)句,其一般格式為classNameobjectName=newclassName(parameterList);此運(yùn)算式隱含了三個(gè)部分,即:對(duì)象說(shuō)明、實(shí)例化和初始化。●對(duì)象說(shuō)明:上面的聲明格式中,classNameobjectName是對(duì)象的說(shuō)明;className是某個(gè)類(lèi)名,用來(lái)說(shuō)明對(duì)象所屬的類(lèi);objectName為對(duì)象名。例如:IntegerIVariable;該語(yǔ)句說(shuō)明IVariable為Integer類(lèi)型?!駥?shí)例化:new是Java實(shí)例化對(duì)象的運(yùn)算符。使用命令new可以創(chuàng)建新的對(duì)象並且為對(duì)象分配記憶體空間。一旦初始化,所有的實(shí)例變數(shù)也將被初始化,即算術(shù)類(lèi)型初始化為0,布爾邏輯型初始化為false,複合類(lèi)型初始化為null。例如:

IntegerIVariable=newInteger(100);

此句實(shí)現(xiàn)將Integer類(lèi)型的對(duì)象IVariable初始值設(shè)為100的功能?!癯跏蓟簄ew運(yùn)算符後緊跟著一個(gè)構(gòu)造方法的調(diào)用。前面我們介紹過(guò),Java中構(gòu)造方法可以重構(gòu),因而通過(guò)給出不同的參數(shù)類(lèi)型或個(gè)數(shù)就可以進(jìn)行不同初始化工作。如例6.3,類(lèi)Rectangle定義了一個(gè)矩形類(lèi),它有多個(gè)不同的構(gòu)造方法,我們可以通過(guò)調(diào)用不同的構(gòu)造方法來(lái)進(jìn)行初始化。例6.3publicclassRectangle{publicintwidth=0;publicintheight=0;publicPointorigin;publicstaticvoidmain(Stringargs[]){Pointp=newPoint(20,20);Rectangler1=newRectangle();Rectangler2=newRectangle(p,80,40);Transcript.println("TheareaofRectangle1is:"+r1.area());Transcript.println("TheareaofRectangle1is:"+r2.area());}publicRectangle(){origin=newPoint(0,0);}publicRectangle(Pointp){origin=p;}publicRectangle(intw,inth){this(newPoint(0,0),w,h);}publicRectangle(Pointp,intw,inth){origin=p;width=w;height=h;}publicvoidmove(intx,inty){origin.x=x;origin.y=y;}publicintarea(){returnwidth*height;}} publicclassPoint{publicintx=0;publicinty=0;圖6.4publicPoint(intx,inty){this.x=x;this.y=y;}}

該例中,我們定義了兩個(gè)類(lèi)Rectangle、Point,並調(diào)用了類(lèi)Rectangle中的area()方法來(lái)求矩形的面積。方法Rectangle()不帶參數(shù),因而只是初始化原點(diǎn)座標(biāo)為(0,0),矩形的長(zhǎng)、寬各為0;方法Rectangle(p,80,40)不僅初始化原點(diǎn)由類(lèi)型Point()指定,同時(shí)還限定矩形的長(zhǎng)、寬各為80、40。此程式的運(yùn)行結(jié)果如圖6.4所示。6.2.2對(duì)象的使用前面我們花了很大的篇幅介紹類(lèi),其目的就是為了掌握如何使用它。類(lèi)是通過(guò)實(shí)例化為對(duì)象來(lái)使用的,而對(duì)象的使用是通過(guò)引用對(duì)象變數(shù)或調(diào)用對(duì)象的方法來(lái)實(shí)現(xiàn)的。與C++相類(lèi)似,對(duì)象變數(shù)和方法均是通過(guò)運(yùn)算符“.”來(lái)實(shí)現(xiàn)的。

1.變數(shù)的引用對(duì)象變數(shù)引用的一般格式為

objectName.variableName

例如:

classexample{ intx;} examplea=newexample(); a.x=100;

變數(shù)的引用在Java中還有一種很特殊的情況,即可以使用運(yùn)算式指定變數(shù)所在的對(duì)象,例如:

intz=newexample().x;

這個(gè)語(yǔ)句創(chuàng)建了一個(gè)新的example對(duì)象,並且得到了它的成員變數(shù)x。需要注意的是,在這條語(yǔ)句被執(zhí)行後,程式不再保留對(duì)象example的引用。這樣,對(duì)象example就被取消引用,因而通過(guò)上述語(yǔ)句並不能達(dá)到初始化對(duì)象的作用。2.對(duì)象方法的引用與對(duì)象變數(shù)引用一樣,對(duì)象方法的引用一般格式為

objectName.methodName([argumentList]);

例如我們?cè)诶?.3中調(diào)用對(duì)象Rectangle中的area()方法計(jì)算矩形的面積:

Transcript.println("TheareaofRectangle1is:"+r1.area());Transcript.println("TheareaofRectangle1is:"+r2.area());

雖然通過(guò)直接引用對(duì)象變數(shù)可以改變對(duì)象的屬性,但是它沒(méi)有任何意義(比如,我們?cè)诶?.3中,使用Rectangle類(lèi)的構(gòu)造方法,可以創(chuàng)建不同的矩形,如果設(shè)置其高h(yuǎn)eight、寬width是負(fù)的,程式並不認(rèn)為其非法)。所以,較好的做法是:不直接對(duì)變數(shù)進(jìn)行操作,而由類(lèi)提供一些方法,對(duì)變數(shù)的引用可以通過(guò)這些方法來(lái)進(jìn)行,以確保給定變數(shù)的數(shù)值是有意義的。這樣一來(lái),Rectangle類(lèi)將提供setWidth、setHeight、getWidth以及getHeight方法來(lái)設(shè)置或者獲得寬度和高度。設(shè)置變數(shù)的方法將在調(diào)用者試圖將width和height設(shè)置為負(fù)數(shù)的時(shí)候給出一個(gè)錯(cuò)誤。這樣能夠更好地體現(xiàn)數(shù)據(jù)的封裝和隱蔽。例如,加上上述的幾個(gè)方法後,例6.3變?yōu)閜ublicclassRectangle{...publicvoidsetWidth(intwidth){ if(width<0) System.out.println("Illegalnumber!"); else this.width=width;}publicvoidsetHeight(intheight){...}publicintgetWidth(){ returnwidth;}publicintgetHeight(){ returnheight;}publicvoidmove(intx,inty){origin.x=x;origin.y=y;}publicintarea(){returnwidth*height;}}6.3類(lèi)的繼承概念Java通過(guò)子類(lèi)實(shí)現(xiàn)繼承。繼承指的是某個(gè)對(duì)象所屬的類(lèi)在層次結(jié)構(gòu)中占一定的位置,具有上一層次對(duì)象的某些屬性。在Java中,所有的類(lèi)都是通過(guò)直接或間接地繼承java.lang.Object類(lèi)得到的,如圖6.5所示。

圖6.5

在類(lèi)的繼承過(guò)程中,被繼承的類(lèi)為父類(lèi)或超類(lèi),繼承得到的類(lèi)為子類(lèi)。父類(lèi)包括所有直接或間接被繼承的類(lèi)。子類(lèi)繼承父類(lèi)的狀態(tài)和行為,也可以修改父類(lèi)的狀態(tài)或重寫(xiě)父類(lèi)的行為(方法),同時(shí)也可以再添加新的狀態(tài)和行為(方法)。需要注意的是,Java與C++不同,不支持多重繼承。同時(shí),為了使繼承更為靈活和完善,Java支持最終類(lèi)和抽象類(lèi)的概念。

所謂的最終類(lèi),同數(shù)結(jié)構(gòu)中的樹(shù)葉節(jié)點(diǎn)一樣,就是不允許對(duì)它進(jìn)行擴(kuò)展的類(lèi),也就是說(shuō)不可以有該類(lèi)的子類(lèi)。實(shí)際使用過(guò)程中,可以在定義類(lèi)時(shí)用關(guān)鍵字final對(duì)它加以說(shuō)明。引入最終類(lèi)的好處是為了提高系統(tǒng)安全性,因?yàn)槿绻兄匾馁Y訊的類(lèi)允許繼承的話,就可能被不懷好意的攻擊者加以利用,從而重要的數(shù)據(jù)就可能被非法修改或洩密。為了防止這些情況發(fā)生,可以將那些重要的類(lèi)說(shuō)明為最終類(lèi),避免非安全事件的發(fā)生。Java中,類(lèi)層次的另一個(gè)概念就是抽象類(lèi),它與最終類(lèi)相對(duì),需要子類(lèi)繼承完善。在類(lèi)的說(shuō)明中我們已討論過(guò),這裏不再詳細(xì)說(shuō)明,只是有幾點(diǎn)注意事項(xiàng)希望讀者留意:

(1)構(gòu)造方法不能定義為抽象方法。

(2)最終方法不能說(shuō)明為抽象方法。

(3)static和private修飾符不能用於抽象方法。

(4)不能重載父類(lèi)中的抽象方法。6.3.1子類(lèi)的創(chuàng)建通過(guò)關(guān)鍵字extends來(lái)創(chuàng)建某個(gè)類(lèi)的子類(lèi),其語(yǔ)法如下:

classsubclassNameextendssuperclassName{...}

例如:

classRectangleextendsShape{...}

這樣,類(lèi)Rectangle就可以繼承父類(lèi)Shape中的成員變數(shù)和方法。前面一些例子中,在作類(lèi)的定義時(shí),並沒(méi)有指明繼承於某個(gè)父類(lèi),比如:

publicclassRectangle{...}

此時(shí),隱含認(rèn)為類(lèi)Rectangle缺省繼承於類(lèi)Object。當(dāng)然,繼承父類(lèi)中的private屬性的變數(shù)和方法也是受限制的,這是大家需要注意的地方。我們可以發(fā)現(xiàn),通過(guò)繼承的關(guān)係,使得成熟的代碼可以獲得重用的好處,大大提高了編程的效率。同時(shí),由類(lèi)封裝而帶來(lái)的數(shù)據(jù)隱藏,也可以提高程式的可維護(hù)性。6.3.2變數(shù)的隱藏繼承給我們帶來(lái)方便,但如果使用中概念不清,也可能會(huì)給我們帶來(lái)一些問(wèn)題。假設(shè)我們實(shí)現(xiàn)了某個(gè)類(lèi)的繼承,當(dāng)子類(lèi)中的成員變數(shù)與父類(lèi)中的成員變數(shù)同名時(shí),應(yīng)該怎麼辦呢?Java解決這一問(wèn)題的辦法是採(cǎi)用所謂的變數(shù)隱藏機(jī)制。也就是說(shuō),如果該種情況發(fā)生,則父類(lèi)中的變數(shù)將被隱藏起來(lái)。例如:

classsuperClass{ intsameVariable; ...}classsubClassextendssuperClass{ intsameVariable//此時(shí),此處變數(shù)sameVariable隱藏了父類(lèi)的同名變數(shù)

...}

可能有的讀者會(huì)說(shuō),那我非要用父類(lèi)中的同名變數(shù),應(yīng)該怎麼辦呢?其實(shí)我們前面討論構(gòu)造方法時(shí)已經(jīng)提到過(guò):當(dāng)引用父類(lèi)中的變數(shù)時(shí),必須使用super關(guān)鍵字。classsubClassextendssuperClass{ intsameVariable //此時(shí),此處變數(shù)sameVariable隱藏了父類(lèi)的同名變數(shù)

...

System.out.println( "NowoutputtheSuperClassvariable!"+super.sameVariable);//引用父類(lèi)中的變數(shù)

}6.3.3方法置換與我們前面所介紹的方法重載很相似,Java中的方法置換指的是子類(lèi)中的方法名與父類(lèi)中的某個(gè)方法名相同,此時(shí),子類(lèi)中的同名方法就被稱(chēng)為置換方法。置換方法與父類(lèi)中的同名方法具有相同的方法名、相同的返回值類(lèi)型和相同的參數(shù)表。如果要調(diào)用父類(lèi)中的同名方法,也使用關(guān)鍵字super進(jìn)行首碼修飾。例如:例6.4

packageuntitled4;importgenesis.*;publicclassMyClass1{ intx,y; publicMyClass1(){} publicMyClass1(intx,inty){ this.x=x;this.y=y;} publicvoidtest(){ Transcript.println("x,yinsuperclassis:"+x+""+y);}}

packageuntitled4; importgenesis.*; publicclassMyClass2extendsMyClass1{ intx,y; publicMyClass2(intx,inty){ this.x=x; this.y=y;} publicstaticvoidmain(Stringargs[]){ MyClass2m2=newMyClass2(10,20); MyClass1m1=m2; m1.test();m2.test();} publicvoidtest(){ super.test();Transcript.println("x,yinsubclassis:"+x+""+y); }}運(yùn)行結(jié)果如圖6.6所示。請(qǐng)讀者仔細(xì)分析程式的執(zhí)行結(jié)果。圖6.66.4Java中介面與包的概念

在上一小節(jié)我們討論了Java中的一個(gè)重要特徵:繼承機(jī)制。由於Java只支持單一繼承,即一個(gè)子類(lèi)只有一個(gè)父類(lèi)(與C++不同),但實(shí)際的開(kāi)發(fā)過(guò)程中,可能會(huì)碰到需要多重繼承的情況,這應(yīng)該怎麼辦呢?Java中的介面機(jī)制為我們提供了實(shí)現(xiàn)多重繼承的可能。介面的概念較C++中的多重繼承概念要簡(jiǎn)單、方便,它可以達(dá)到多個(gè)不相關(guān)的類(lèi)具有相同的方法這一特殊效果。6.4.1介面介面是一系列沒(méi)有實(shí)現(xiàn)的方法和常量的組合,它提供方法協(xié)議的封裝,但不限制子類(lèi)如何實(shí)現(xiàn)這些方法,從而使得類(lèi)的繼承變得簡(jiǎn)單而靈活。通過(guò)介面我們可以使處?kù)恫煌瑢哟?、互不相干的?lèi)具有相同的行為??偟膩?lái)說(shuō),介面的功能可以歸納為如下幾點(diǎn):(1)通過(guò)介面可以實(shí)現(xiàn)不相干類(lèi)的相同行為而不需考慮這些類(lèi)之間的層次關(guān)係。

(2)通過(guò)介面可以指明多個(gè)類(lèi)需要實(shí)現(xiàn)的方法。

(3)通過(guò)介面可以瞭解對(duì)象的交互介面而不需瞭解對(duì)象所對(duì)應(yīng)的類(lèi)。

Java中的介面的基本組成如圖6.7所示。

publicinterfaceinterfaceName{finalStringname="Name";finalStringsex="male";...voidaInterfaceExample(parameterList);}圖6.7publicinterfaceinterfaceName{finalStringname="Name";finalStringsex="male";…voidaInterfaceExample(parameterList);}介面聲明介面體常量定義方法聲明

圖6.7給出了一個(gè)介面的常見(jiàn)聲明格式。介面聲明定義了各種關(guān)於介面的屬性,如它的名字和是否擴(kuò)展其他的屬性等;介面實(shí)體包含了常數(shù)和用於介面的方法聲明。

1.介面的聲明與類(lèi)的聲明格式相似,介面的聲明格式如下:

ModifiersinterfaceinterfaceName[extendssuperinterface_List]

{interfaceBody}

在介面定義中,必須有兩個(gè)元素:interface關(guān)鍵字和介面的名字,其他均為可選項(xiàng)。如果訪問(wèn)限制為public,則表示介面可以在任何包的任何類(lèi)中使用。如果沒(méi)有指定介面為public,那麼介面就只能在定義介面的包的類(lèi)中使用了。介面隱含修飾符為abstract,當(dāng)然,也可以顯式指明為abstract,但是沒(méi)有必要。

介面定義可以有另外一個(gè)選項(xiàng):superinterface_List系列。一個(gè)介面可以通過(guò)關(guān)鍵字extends擴(kuò)展另外的介面,這跟類(lèi)可以擴(kuò)展的概念一樣。但是,類(lèi)只能擴(kuò)展一個(gè)另外的類(lèi),而介面可以擴(kuò)展任意多個(gè)介面。Superinterface_List系列以逗號(hào)(,)分隔的所有介面,這些介面可以由新的介面擴(kuò)展。我們知道,在類(lèi)的擴(kuò)展中,所有的類(lèi),其超類(lèi)均為Object,而介面沒(méi)有所謂的超介面。介面實(shí)體為所有包含在介面中的方法及變數(shù)。

所有定義在介面中的方法隱含為public和abstact。所有定義在介面中的常量可以是public、static和final,介面中的變數(shù)隱含為靜態(tài)變數(shù)(static)。定義在介面中的成員聲明不允許使用某些聲明修飾語(yǔ),比如不能在介面中的成員聲明中使用transient、volatile或者synchronized。同樣,不能在聲明介面成員的時(shí)候使用private和protected修飾語(yǔ)。

另外一點(diǎn)需要注意的是,介面中的方法不能有方法體,所以實(shí)現(xiàn)介面的類(lèi)必須實(shí)現(xiàn)介面中的所有方法。例如:

publicinterfaceMyinterfaceextendssuperinterface{ Stringname; finalintx=10; voidMymethod(intx,inty); ...}2.介面的實(shí)現(xiàn)

Java中提供介面的目的當(dāng)然是為了使用它,用戶(hù)定義的類(lèi)要使用某個(gè)介面時(shí),必須首先實(shí)現(xiàn)這一介面??梢酝ㄟ^(guò)關(guān)鍵字implements說(shuō)明該類(lèi)要實(shí)現(xiàn)的一個(gè)或多個(gè)介面,之後在類(lèi)體中完成介面所有方法的代碼。如此才能使用被實(shí)現(xiàn)了的方法。實(shí)際使用中,可能會(huì)碰到實(shí)現(xiàn)介面的類(lèi)是抽象類(lèi),這樣,完善介面方法的任務(wù)就必須由該類(lèi)的子類(lèi)來(lái)完成。例如:publicclassinterfaceExampleimplementsRunnable{ ThreadmyThread; ... publicvoidrun(){ ... //實(shí)現(xiàn)介面中的Runnable方法

} ...}

當(dāng)定義一個(gè)新的介面時(shí),從本質(zhì)上講,就好像定義

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 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ì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論