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

下載本文檔

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

文檔簡介

Java中類、對象、介面及

包的概念6.1類的基本概念

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

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

①電梯

②街頭的自動售貨機

③街上跑的汽車

④凳子

⑤人

……

上面列舉的對象都有兩個共性:

(1)具有一定的狀態(tài)和特性。比如汽車有輪胎、發(fā)動機、方向盤等。

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

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

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

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

[extendssuperclassName][implementsinterfaceNameList] {...}

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

publicclassstack {...}

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

classclassName{

variableDeclaration methodDeclaration }

讀者可參照圖6.1仔細(xì)體會類體所包含的內(nèi)容。

1.變數(shù)

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

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

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

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

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

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

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

classMyClass{publicfloatvariable1;publicstaticintvariable2}

該例中聲明了一個實例變數(shù)variable1和一個類變數(shù)variable2。今後當(dāng)我們創(chuàng)建類的實例的時候,系統(tǒng)就會為該實例創(chuàng)建一個類實例的副本,但系統(tǒng)為每個類分配類變數(shù)僅僅只有一次,而不管類創(chuàng)建的實例有多少。當(dāng)?shù)谝淮握{(diào)用類的時候,系統(tǒng)為類變數(shù)分配記憶體。所有的實例共用了類的類變數(shù)的相同副本。在程式中可通過一個實例或者類本身來訪問類變數(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)我們從類實例化新對象的時候,就得到了類實例變數(shù)的一個新副本。這些副本跟新對象是聯(lián)繫在一起的。因此,每實例化一個新MyClass對象的時候,就得到了一個和MyClass對象有聯(lián)繫的variable1的新副本。當(dāng)一個成員變數(shù)用關(guān)鍵字static被指定為類變數(shù)後,其第一次調(diào)用的時候,系統(tǒng)就會為它創(chuàng)建一個副本,之後,類的所有實例均共用了該類變數(shù)的相同副本。所以上述程式段的輸出結(jié)果為

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

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

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

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

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

returnTypemethodName()

{...}

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

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

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

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

classShape{ abstractvoiddraw();}

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

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

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

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

當(dāng)我們傳遞不同的參數(shù)時,構(gòu)造出來的對象的實例具有不同的屬性。3)方法中參數(shù)的使用在方法的聲明格式中,需要指明返回值的類型。當(dāng)一個方法不需要返回值的時候,其類型說明為void,否則方法體中必須包含return語句。返回值既可以是基本數(shù)據(jù)類型,也可以是複雜數(shù)據(jù)類型。在C語言、PASCAL語言中,函數(shù)、過程的參數(shù)都存在值傳遞/參數(shù)傳遞的問題。比如C語言中如果參數(shù)是指針或數(shù)組名則為參數(shù)傳遞。我們知道,Java中由於取消了指針,不可能像C一樣直接操作記憶體,但是由於對象的動態(tài)聯(lián)編性,複雜數(shù)據(jù)類型作參數(shù)相當(dāng)於指針的使用,即參數(shù)傳遞,而基本數(shù)據(jù)類型作參數(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);} }運行結(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); }}運行後的結(jié)果如圖6.3所示。圖6.3

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

classswapByAddress{ intx,y; public

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

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

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

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

newStack(10);

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

newStack();

另外,如果生成的類不為它提供構(gòu)造方法,系統(tǒng)會自動提供缺省的構(gòu)造方法。這個缺省的構(gòu)造方法不會完成任何事情。下例給出類AnimationThread的構(gòu)造方法,在其初始化過程中設(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++){...}}...}

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

super("AnimationThread");

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

protectedvoidfinalize(){...}

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

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

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

protected√√√

public√√√√friendly√

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

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

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

classA{privateintprivateVariable;

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

結(jié)果是運行正常。可見,相同類型的對象可以訪問其他對象的private成員。這是因為訪問限制只是在類別層次(類的所有實例)而不是在對象層次(類的特定實例)上。

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

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

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

tectMethod(); //合法

}}

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

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

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

tectMethod();//非法

tectMethod();//合法

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

a.publicMethod();//合法

}}

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

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

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

a.friendMethod(); //合法

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

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

IntegerIVariable=newInteger(100);

此句實現(xiàn)將Integer類型的對象IVariable初始值設(shè)為100的功能?!癯跏蓟簄ew運算符後緊跟著一個構(gòu)造方法的調(diào)用。前面我們介紹過,Java中構(gòu)造方法可以重構(gòu),因而通過給出不同的參數(shù)類型或個數(shù)就可以進(jìn)行不同初始化工作。如例6.3,類Rectangle定義了一個矩形類,它有多個不同的構(gòu)造方法,我們可以通過調(diào)用不同的構(gòu)造方法來進(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;}}

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

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

objectName.variableName

例如:

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

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

intz=newexample().x;

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

objectName.methodName([argumentList]);

例如我們在例6.3中調(diào)用對象Rectangle中的area()方法計算矩形的面積:

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

雖然通過直接引用對象變數(shù)可以改變對象的屬性,但是它沒有任何意義(比如,我們在例6.3中,使用Rectangle類的構(gòu)造方法,可以創(chuàng)建不同的矩形,如果設(shè)置其高h(yuǎn)eight、寬width是負(fù)的,程式並不認(rèn)為其非法)。所以,較好的做法是:不直接對變數(shù)進(jìn)行操作,而由類提供一些方法,對變數(shù)的引用可以通過這些方法來進(jìn)行,以確保給定變數(shù)的數(shù)值是有意義的。這樣一來,Rectangle類將提供setWidth、setHeight、getWidth以及getHeight方法來設(shè)置或者獲得寬度和高度。設(shè)置變數(shù)的方法將在調(diào)用者試圖將width和height設(shè)置為負(fù)數(shù)的時候給出一個錯誤。這樣能夠更好地體現(xiàn)數(shù)據(jù)的封裝和隱蔽。例如,加上上述的幾個方法後,例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類的繼承概念Java通過子類實現(xiàn)繼承。繼承指的是某個對象所屬的類在層次結(jié)構(gòu)中占一定的位置,具有上一層次對象的某些屬性。在Java中,所有的類都是通過直接或間接地繼承java.lang.Object類得到的,如圖6.5所示。

圖6.5

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

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

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

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

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

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

classsubclassNameextendssuperclassName{...}

例如:

classRectangleextendsShape{...}

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

publicclassRectangle{...}

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

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

...}

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

...

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

}6.3.3方法置換與我們前面所介紹的方法重載很相似,Java中的方法置換指的是子類中的方法名與父類中的某個方法名相同,此時,子類中的同名方法就被稱為置換方法。置換方法與父類中的同名方法具有相同的方法名、相同的返回值類型和相同的參數(shù)表。如果要調(diào)用父類中的同名方法,也使用關(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); }}運行結(jié)果如圖6.6所示。請讀者仔細(xì)分析程式的執(zhí)行結(jié)果。圖6.66.4Java中介面與包的概念

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

(2)通過介面可以指明多個類需要實現(xiàn)的方法。

(3)通過介面可以瞭解對象的交互介面而不需瞭解對象所對應(yīng)的類。

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

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

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

1.介面的聲明與類的聲明格式相似,介面的聲明格式如下:

ModifiersinterfaceinterfaceName[extendssuperinterface_List]

{interfaceBody}

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

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

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

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

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

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

} ...}

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

溫馨提示

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

評論

0/150

提交評論