定義類別(Class) | Java SE 6 技術手冊 - caterpillar

文章推薦指數: 80 %
投票人數:10人

在Java 中使用"class" 關鍵字來定義類別,使用類別來定義一個物件(Object)時,會考慮這個物件可能擁有的「屬性」(Property)與「方法」(Method)。

JavaSE6技術手冊 關於JavaSE6技術手冊 1. 瞭解Java 1.1. 什麼是Java 1.2. Java的特性 1.3. 如何學習Java 1.4. 接下來的主題 2. 入門準備 2.1. 下載、安裝、瞭解JDK 2.2. 設定Path與Classpath 2.3. 第一個Java程式 2.4. 選擇開發工具 2.5. 接下來的主題 3. 語法入門 3.1. 第一個Java程式 3.2. 在文字模式下與程式互動 3.3. 資料、運算 3.4. 流程控制 3.5. 接下來的主題 4. 從autoboxing、unboxing認識物件 4.1. 關於物件 4.2. 自動裝箱、拆箱 4.3. 接下來的主題 5. 陣列 5.1. 一維陣列、二維陣列 5.2. 進階陣列觀念 5.3. 接下來的主題 6. 字串 6.1. 認識字串 6.2. 字串進階運用 6.3. 接下來的主題 7. 封裝(Encapsulation) 7.1. 定義類別(Class) 7.2. 關於方法 7.3. 接下來的主題 8. 繼承(Inheritance)、多型(Polymorphism) 8.1. 繼承 8.2. 多型(Polymorphism) 8.3. 接下來的主題 9. 管理類別檔案 9.1. 內部類別 9.2. package與import 9.3. 接下來的主題 10. 例外處理(ExceptionHandling) 10.1. 例外處理入門 10.2. 受檢例外(CheckedException)、執行時期例外(RuntimeException) 10.3. throw、throws 10.4. 例外的繼承架構 10.5. 斷言(Assertion) 10.6. 接下來的主題 11. 列舉型態(EnumeratedTypes) 11.1. 常數設置與列舉型態 11.2. 定義列舉型態 11.3. 接下來的主題 12. 泛型 12.1. 泛型入門 12.2. 泛型進階語法 12.3. 接下來的主題 PoweredbyGitBook A A 襯線體 無襯線體 白色 棕褐色 夜間 分享到Twitter 分享到Google 分享到Facebook 分享到Weibo 分享到Instapaper JavaSE6技術手冊 7.1定義類別(Class) 以物件導向的思維來思考一個問題的解答時,會將與問題相關的種種元素視作一個個的物件,問題的發生是由物件的交互所產生,而問題的解答也由某些物件彼此合作來完成。

所以如何描述問題中的各種元素?如何將這些元素定義為物件?也就是如何封裝物件資訊就是物件導向設計的第一步。

您要瞭解如何使用「類別」(Class)定義物件,類別是建構物件時所依賴的規格書。

7.1.1以物件思考問題 簡單的說,物件導向的思維就是以物件為中心來思考問題,然而什麼又叫作「以物件為中心來思考問題」?我不想用太多抽象的字眼來解釋這些詞語,這邊實際提出一個問題,並嘗試以物件導向的方式來思考問題。

有一個帳戶,帳戶中有存款餘額,您可以對帳戶進行存款與提款的動作,並可以查詢以取得存款餘額。

要以物件為中心來思考問題,首先要識別出問題中的物件,以及物件上的屬性與可操作的方法: 識別問題中的物件與屬性 帳戶是個比較單純的問題,可以從問題中出現的名詞來識別出物件,描述中有「帳戶」與「餘額」兩個名詞,基本上兩個名詞都可以識別成物件,然而在這個簡單的問題當中,設計的粒度還不需要這麼細,所以您先識別「帳戶」這個物件。

識別出物件之後,接下來看看物件上有什麼屬性(Property),像是物件上擁有什麼特徵或是可表示的狀態(State),屬性是物件上的靜態特性。

屬性基本上也可以從名詞上識別,在這個例子中,您可以將「餘額」作為帳戶的屬性之一。

圖7.1識別出物件與屬性 識別物件上的方法 接著要識別物件上的方法,也就是識別物件上的動態特性,也就是物件本身可操作或供操作的介面,問題描述上的動詞可能就可以識別為方法,例如「存款」、「提款」、「查詢餘額」等動作,就可以識別為物件上的方法。

圖7.2識別物件方法 識別出物件及其上的屬性與方法之後,您就有了基本的物件定義書,接著您就可以實際從定義書中產生物件實例,並以這些物件實例設計彼此間的交互行為以解決問題。

圖7.3從物件定義書中產生物件實例 如何為這些物件實例設計交互行為,依應用的領域不同而有所差異,就Java程式設計而言,就是使用Java的語法來為這些物件來進行各種條件判斷與流程控制,接著運行程式以獲得解答。

良葛格的話匣子以上是很簡單的物件分析過程,目的在讓您對物件導向分析有大致的瞭解,對於真正所面臨的問題,實際的物件分析會再複雜一些,例如單純從問題中的名詞來識別物件就不一定行的通了,這與「物件導向分析」(Object-orientedAnalysis)有關,如果您想進一步瞭解物件導向分析,建議看看這本書: ApplyingUMLandPatterns:AnIntroductiontoObject-OrientedAnalysisandDesignandtheUnifiedProcess,SecondEditionByCraigLarman 7.1.2使用class定義類別 在物件導向設計中,物件並不會憑空產生,您必須識別出問題中的物件,並對這些物件加以定義,您要定義一個規格書,在Java中這個規格書稱之為「類別」(Class),您使用類別定義出物件的規格書,之後根據類別來建構出一個個的物件,然後透過物件所提供的操作介面來與程式互動。

在Java中使用"class"關鍵字來定義類別,使用類別來定義一個物件(Object)時,會考慮這個物件可能擁有的「屬性」(Property)與「方法」(Method)。

屬性是物件的靜態表現,而方法則是物件與外界互動的動態操作。

舉個例子來說,若您的問題中會有「帳戶」這個物件,在分析了您的問題之後,您為「帳戶」這個物件定義了Account類別。

範例7.1Account.java publicclassAccount{ privateStringaccountNumber; privatedoublebalance; publicAccount(){ this("empty",0.0); } publicAccount(StringaccountNumber,doublebalance){ this.accountNumber=accountNumber; this.balance=balance; } publicStringgetAccountNumber(){ returnaccountNumber; } publicdoublegetBalance(){ returnbalance; } publicvoiddeposit(doublemoney){ balance+=money; } publicdoublewithdraw(doublemoney){ balance-=money; returnmoney; } } 在這邊先大致呈現出一個類別所可能具備的元素並加以簡介,稍後對每個元素會詳加介紹: 定義類別 首先看到範例中的"class",這是Java中用來定義類別的關鍵字,記得一個類別的定義是這麼作的: publicclassAccount{ //實作內容 } Account是您為類別取的名稱,由於這個類別使用"public"關鍵字加以修飾,所以檔案的主檔名必須與類別名稱相同,也就是檔案要取名為"Account.java",這是規定,在一個檔案中可以定義數個類別,但只能有一個類別被設定為"public",檔案名稱主檔名必須與這個public的類別同名,例如Account.java中可以有以下的內容: publicclassAccount{//檔案必須是Account.java //實作內容 } classSomeClass{ //實作內容 } classOtherClass{ //實作內容 } 定義成員 在類別中的資料及互動方法,統稱其為「類別成員」(Classmember),範例7.1中的accountNumber、balance成員是「資料成員」(Fieldmember),getAccountNumber()與getBalance()是「方法成員」(Methodmember),在定義資料成員時可以指定初值,如果沒有指定初值,則會有預設值,資料成員如果是基本型態,則預設值與表5.1所列出的相同,如果是物件型態,則預設值為null,也就是不參考任何的物件。

注意到"public"這個關鍵字,這表示所定義的成員可以使用宣告的物件名稱加上'.'運算子來直接呼叫,也稱之為「公用成員」或「公開成員」。

"private"這個關鍵字用來定義一個「私用成員」,私用成員不可以透過參考名稱加上"."直接呼叫,又稱之為「私有成員」。

在定義類別時,有一個基本原則是:資訊的最小化公開。

也就是說儘量透過方法來操作物件,而不直接存取物件內部的資料成員(也就是Field成員)。

資訊的最小化公開原則是基於安全性的考量,避免程式設計人員隨意操作內部資料成員而造成程式的錯誤,您可以在日後的程式設計中慢慢來體會;在稍後的實作中,您將看到我不會對accountNumber與balance兩個私用成員直接存取,而會透過公開的方法來對它們進行設定。

一個類別中的資料成員,若宣告為"private",則其可視範圍(Scope)為整個類別內部,由於外界無法直接存取私用成員,所以您要使用兩個公開方法getAccountNumber()與getBalance()分別傳回其這兩個成員的值。

定義建構方法 與類別名稱同名的方法稱之為「建構方法」(Constructor),也有人稱之為「建構子」,它沒有傳回值,建構方法的作用是讓您建構物件的同時,可以同時初始一些必要的資訊,建構方法可以被「重載」(Overload),以滿足物件生成時各種不同的初始需求,在範例7.1中您重載了建構方法,在不指定引數的情況下,會將balance設定為0.0,而accountNumber設定為"empty",另一個建構方法則可以指定引數,this()方法用於物件內部,表示呼叫物件的建構方法,另一個關鍵字就是"this",它參考至物件本身,7.1.5會再詳細介紹"this"以進一步瞭解其作用。

定義好Account類別之後,您就可根據這個類別來建構物件,也就是產生Account類別的實例,建構物件時要使用"new"關鍵字,顧名思義,就是根據所指定的類別(規格書)「新建」一個物件: Accountaccount1=newAccount(); Accountaccount2=newAccount("123-4567",100.0); 在上面的程式片段中宣告了account1與account2兩個Account型態的參考名稱,並讓它們分別參考至物件,account1所參考的物件在建立時並不指定任何引數,所以根據之前對Account類別的定義,account1所參考物件的balance將設定為0.0,accountNumber設定為"empty";accont2所參考的物件在新建時則給定兩個引數,所以account2所參考物件的balance設定為100.0,而accountNumber設定為"empty"。

要透過公開成員來操作物件或取得物件資訊的話,可以在物件名稱後加上「.」運算子來進行,例如: account1.getBalance(); account1.deposit(1000.0); 範例7.2綜合以上的介紹來作個簡單的練習,要使用到範例7.1中的Account類別。

範例7.2AccountDemo.java publicclassAccountDemo{ publicstaticvoidmain(String[]args){ Accountaccount=newAccount(); System.out.println("帳戶:"+account.getAccountNumber()); System.out.println("餘額:"+account.getBalance()); account=newAccount("123-4567",100.0); account.deposit(1000.0); System.out.println("帳戶:"+account.getAccountNumber()); System.out.println("餘額:"+account.getBalance()); } } Account.java與AccountDemo.java都要編譯,然後執行程式,結果如下: 帳戶:empty 餘額:0.0 帳戶:123-4567 餘額:1100.0 良葛格的話匣子類別與物件這兩個名詞會經常混於書籍與文件之中,例如「您可以使用Scanner類別」、「您可以使用Scanner物件」,這兩句在某些場合其意思可能是相同的,不過要細究的話,兩句的意思通常都是「您可以使用根據Scanner類別所建構出來的物件」,不過寫這麼長很煩,難免就省略了一些字眼。

7.1.3類別成員(Classmember) 在Java中,一個類別可以定義資料成員(Field)及方法(Method)成員,在Java中,類別成員可用的存取權限修飾詞有"public"、"protected"、"private"三個,如果在宣告成員時不使用存取修飾詞,則預設以「套件」(package)為存取範圍,也就是說在package外就無法存取,關於package與存取修飾的關係,在第9章還會見到說明。

以範例7.1為例來進行說明。

在該範例中,您定義了一個Account類別,當中還定義了accountNumber與balance兩個資料成員,這兩個資料成員被宣告為"private",表示它是「私用成員」(Privatemember),私用成員只能在Account類別中被使用,不可以直接藉由物件的參考名稱加上"."來直接存取它。

再來看到方法(Method)成員,範例7.1的每一個方法被宣告為"public",表示這些方法可以藉由物件的參考名稱加上"."直接呼叫,一個方法成員為一小個程式片段或一個執行單元(Unit),這個程式片段可重複被呼叫使用,並可傳入引數或傳回一個表示執行結果的數值,一個方法成員的基本宣告與定義方式如下: 存取修飾傳回值型態方法名稱(參數列){   //實作   return傳回值; } 參數列用來傳入方法成員執行時所需的資料,如果傳入的引數是基本資料型態(Primitivedatatype),則會將值複製至參數列上的參數,如果傳入的引數是一個物件,則會將參數列上宣告的參數參考至指定的物件。

方法區塊中可以宣告變數(Variable),參數在方法區塊執行結束後就會自動清除,如果方法中宣告的變數名稱與類別資料成員的名稱同名,則方法中的變數名稱會暫時覆蓋資料成員的作用範圍;參數列上的參數名稱也會覆蓋資料成員的作用範圍,如果此時要在方法區塊中使用資料成員,可以使用"this"關鍵字來特別指定,範例7.3可以印證這個說明。

範例7.3MethodMember.java publicclassMethodMember{ publicstaticvoidmain(String[]args){ MethodDemomethodDemo=newMethodDemo(); methodDemo.scopeDemo();//對data資料成員不會有影響 System.out.println(methodDemo.getData()); methodDemo.setData(100);//對data資料成員不會有影響 System.out.println(methodDemo.getData()); } } classMethodDemo{ privateintdata=10; publicvoidscopeDemo(){//void表示沒有傳回值 intdata=100; } publicintgetData(){ returndata; } publicvoidsetData(intdata){//void表示沒有傳回值 data=data;//這樣寫是沒用的 //寫下面這個才有用 //this.data=data; } } 執行結果: 10 10 方法的傳回值可以將計算的結果或其它想要的數值、物件傳回,傳回值與傳回值型態的宣告必須一致,在方法中如果執行到"return"陳述,則會立即終止區塊的執行;如果方法執行結束後不需要傳回值,則可以撰寫"void",且無需使用"return"關鍵字。

在物件導向程式設計的過程中,有一個基本的原則,如果資料成員能不公開就不公開,在Java中若不想公開成員的資訊,方式就是宣告成員為"private",這是「資訊的最小化」,此時在程式中要存取"private"成員,就要經由setXXX()與getXXX()等公開方法來進行設定或存取,而不是直接存取資料成員。

透過公開方法存取私用成員的好處之一是,如果存取私用成員的流程有所更動,只要在公開方法中修改就可以了,對於呼叫方法的應用程式不受影響,例如您的Account類別中,withdraw()顯然的在餘額為0時,仍然可以提款,您必須對此做出修正: publicdoublewithdraw(doublemoney){ if(balance–money<0){ return0; } else{ balance-=money; returnmoney; } } 這麼一來,您的withdraw()對balance做了些檢查,但對於使用Account的AccountDemo來說,並不用做出修改。

在第4章中介紹過autoboxing、unboxing,在方法的參數列中是可以作用的,也就是說如果您的方法中是這樣設計的: publicclassSomeClass{ .... publicvoidsomeMethod(Integerinteger){ ...... } .... } 則您可以使用這樣的方式來設定引數: SomeClasssomeObj=newSomeClass(); someObj.someMethod(1);//autoboxing 良葛格的話匣子方法名稱的命名慣例為首字小寫,名稱以一目瞭解方法的作用為原則,以上所採取的都是駱駝式的命名方式,也就是每個單字的首字予以適當的大寫,例如someMethodOfSomeClass()這樣的命名方式。

為資料成員設定setXXX()或getXXX()存取方法時,XXX名稱最好與資料成員名稱相對應,例如命名balance這個資料成員對應的方法時,可以命名為setBalance()與getBalance(),而accountNumber這個成員,則可對應於setAccountNumber()與getAccountNumber()這樣的名稱,如此閱讀程式時可以一目瞭解方法的存取對象。

您搞得清楚「參數」(Parameter)與引數(Argument)嗎?在定義方法時,可以定義「參數列」,例如: publicvoidsetSomething(intsomething){//something稱之為參數 //... } 而呼叫方法時傳遞的數值或物件稱之為「引數」,例如: someObject.setSomething(10);//10是引數 7.1.4建構方法(Constructor) 在定義類別時,您可以使用「建構方法」(Constructor)來進行物件的初始化,在Java中建構方法是與類別名稱相同的公開方法成員,且沒有傳回值,例如: publicclassSafeArray{ //.. publicSafeArray(){//建構方法 //.... } publicSafeArray(參數列){// //.... } } 在建構方法中,您可以定義無參數的或具有參數的建構方法,程式在運行時,會根據配置物件時所指定的引數資料型態等,來決定該使用哪一個建構方法新建物件,如果您沒有定義任何的建構方法,則編譯器會自動配置一個無參數且沒有陳述內容的建構方法。

在範例7.4示範了實作簡單的「安全的陣列」,您所定義的陣列類別可以動態配置陣列長度,並可事先檢查存取陣列的索引是否超出陣列長度,在這個陣列類別中,您還實作了幾個簡單的功能,像是傳回陣列長度、設定陣列元素值、取得陣列元素值等。

範例7.4SafeArray.java publicclassSafeArray{ privateint[]arr; publicSafeArray(){ this(10);//預設10個元素 } publicSafeArray(intlength){ arr=newint[length]; } publicvoidshowElement(){ for(inti:arr){ System.out.print(i+""); } } publicintgetElement(inti){ if(i>=arr.length||i<0){ System.err.println("索引錯誤"); return0; } returnarr[i]; } publicintgetLength(){ returnarr.length; } publicvoidsetElement(inti,intdata){ if(i>=arr.length||i<0){ System.err.println("索引錯誤"); return; } arr[i]=data; } } 如果您不指定引數的話,就會使用無參數的建構方法來配置10個元素的陣列,您也可以由指定的長度來配置陣列;您在無參數的建構方法中使用this(10),這會呼叫另一個有參數的建構方法,以避免撰寫一些重複的原始碼。

範例7.5示範了如何使用自訂的安全陣列類別。

範例7.5SafeArrayDemo.java publicclassSafeArrayDemo{ publicstaticvoidmain(String[]args){ //預設10個元素 SafeArrayarr1=newSafeArray(); //指定配置5個元素 SafeArrayarr2=newSafeArray(5); for(inti=0;i



請為這篇文章評分?