官术网_书友最值得收藏!

4.1 類的方法

如2.3節所述,方法是類定義的主要組成部分,是對類中域變量進行操作的程序單元。Java語言的方法必須在類中,不能有位于類之外的方法。

4.1.1 方法的定義

Java語言中方法定義的一般格式是:

     [修飾符]  返回值類型 方法名(類型 參數名1, 類型 參數名2, …)
     { // 這對大括號內是方法體
         一些變量聲明語句
         一些執行語句
         return 表達式;
     }

其中,修飾符是可選的,可以限定該方法的可見范圍或其他特性,隨后介紹。

(1)返回值類型:方法完成對數據的計算和處理等操作之后獲得了處理結果,可能需要將結果返回給請求這個方法的對象,返回值類型告訴該方法會返回什么類型的數據。方法的具體返回值就是return語句后表達式的值。如果沒有返回數據,則用void關鍵字說明,此時return語句后沒有表達式部分,或者干脆不要return語句。例如,前面例題中自動生成的事件處理方法(如addNumber)就沒有返回值,其返回值類型為void,方法體中沒有return語句。

(2)方法名:為該方法取的在該類中的唯一名字,符合Java標識符規則。對象等通過方法名請求該方法。一般方法名的第一個字母小寫。

(3)參數表:在方法名后的一對小括號內定義,聲明了每個參數的類型和參數名。如果有多個參數,使用逗號“,”分隔。

從Java 5開始還可以在方法參數表中定義一個可變元參數,即參數個數不確定而參數類型確定的參數表。可變元參數必須在整個參數表的最后,形式是:類型…參數名。例如:

     int calcAvg(float avg, int...values) {
        // …
        return avg;
     }

(4)變量聲明:方法體中聲明的變量一般是計算過程中使用的一些中間變量,它的使用范圍是在該方法體內,出了這個方法的最后一個大括號“}”,這些變量就不能使用了,因此叫作局部變量

事實上,在任何一個語句塊內定義的變量都是局部變量,出了這個語句塊范圍就不能使用。局部變量必須在使用之前初始化,如果沒有賦初值則不能獲得一個默認值,而是保存有一個隨機值。

Java 10中可以采用“var變量名=初值;”的方式定義局部變量,Java 10會根據初值的類型推斷此變量的類型,此后在其作用域范圍內會保持其類型。例如,語句“var x=10;”則使變量x為int類型,此后若執行語句“x=10.1;”會發生類型不兼容錯誤。應注意,在定義字段變量,方法的參數及方法返回值的類型時,不能使用保留字var。

(5)執行語句:方法體中的執行語句對類的域變量、方法體中的局部變量及參數變量進行操作,可以是賦值語句、流程控制語句以及調用其他方法的語句等。方法體內可以直接使用它本身定義的局部變量、該方法的參數變量以及方法所在類中的域變量。

例如,例3.4四則運算計算器程序中“=”按鈕的鼠標單擊事件處理方法(見圖4.1),方法名是calcOpr;void表示該方法無返回值;參數表中只有一個參數——參數類型是java.awt.event.ActionEvent類,參數名是evt;118行稱為方法頭。該方法體中定義了6個局部變量,strNum1、strNum2和opr是String類型,num1、num2和result是int類型;其中,strNum1和strNum2的作用范圍是整個calcOpr方法,其余4個局部變量作用范圍是122~143行的if語句塊;使用if、if-else-if語句、賦值語句、jTextFieldResult對象的setText和getText等方法調用以及jComboBoxOpr對象的getSelectedItem方法調用等執行語句根據用戶選擇的運算種類獲得運算結果,并將結果使用文本字段組件顯示出來。

圖4.1 例3.4程序“=”按鈕事件處理方法

4.1.2 方法的調用及參數傳遞

對類的對象中方法的執行請求就是對該方法的調用。請求執行方法的對象是調用者,而被請求執行的方法是被調用方法。例如,在book.ifdemos.ArithmeticClac類的calcOpr方法中調用了jTextFieldNum1對象的getText方法(見圖4.1第120行語句),方法調用者就是calcOpr方法所屬的對象;又如,chap03項目的ArithmeticClac.java文件中的以下程序段:

在第53行調用了calcOpr方法,方法調用者和被調用方法屬于同一個對象。

方法調用的一般形式是:

     對象名.方法名(參數表);

(1)對象名:該對象名是被調用方法所屬的對象。例如,圖4.1第120行語句的對象名jTextFieldNum1指明調用的getText方法是第一個文本字段組件(對象)的方法,而不是第二個文本字段組件或顯示運算結果文本字段組件的getText方法。如果被調用方法與調用者是同一個對象,則可以省略方法名前面的對象名,例如上段代碼的第53行。

(2)參數表:此參數表是一些表達式、常量或變量組成的列表,每個參數都有一個確定值,與方法定義時的參數表所列的參數的類型、次序和個數一一對應,多個參數之間用逗號“,”分隔。方法定義時的參數稱為形式參數,簡稱形參,參數表也叫形參表;方法調用時給出的參數稱為實際參數,簡稱實參,參數表也叫實參表。例如,如圖4.1所示calcOpr方法定義的形參表只有一個形參evt,形參類型是java.awt.event.ActionEvent類,上段代碼第53行調用calcOpr方法時給出的實參是變量evt,evt是第52行聲明的java.awt.event.ActionEvent類的對象。

在調用具有可變元參數的方法時,實參也要與形參對應。例如,前面定義的方法calcAvg,調用時第一個實參必須是float類型的,后面是多個int類型的實參,如“calcAvg(3.2f, 3, 5, 10, 40);”是正確的,但是“calcAvg(3.2f, 3, 5, 10.0, 40);”則是錯誤的,因為第4個實參類型并不是int。

Java程序中方法的調用是按值調用,即調用者將實參的值傳遞給被調方法對應的形參。如果方法的參數是基本數據類型,則實參向形參傳值的過程十分直觀,就是形參復制了實參的值,在方法中對形參的改變不會影響實參。

例4.1 編寫方法swap交換兩個int型變量的值,并顯示交換前后形參和實參的值。

解:按照以下步驟操作。

(1)在NetBeans IDE中創建一個Java應用程序項目,項目名稱為chap04。

(2)創建包book.methoddemos,并在該包中新建JFrame窗體,類名為VarSwap。

(3)設計如圖4.2所示的界面,其中,文本字段組件jTextFieldVar1和jTextFieldVar2分別用于輸入兩個整數,jTextFieldVar1A和jTextFieldVar2A分別顯示調用交換方法swap后實參的值,jTextFieldArg1和jTextFieldArg2分別顯示調用交換方法swap前形參的值,jTextFieldArg1A和jTextFieldArg2A分別顯示調用交換方法swap后形參的值。這8個文本字段組件的columns屬性值設置為8,除jTextFieldVar1和jTextFieldVar2之外的其他6個editable屬性值都設置為false。其余組件按照圖4.2導航器窗口中內容命名。

圖4.2 例4.1程序界面設計視圖

(4)在VarSwap類中設計方法swap,源代碼如下。

(5)為“交換”按鈕jButtonSwap組件添加actionPerformed事件處理方法swapVars,該方法源代碼如下。

(6)為“清除”按鈕jButtonClear組件添加actionPerformed事件處理方法clearAll,該方法源代碼如下。

     private void clearAll(java.awt.event.ActionEvent evt) {
         // TODO add your handling code here:
         jTextFieldVar1.setText("");
         jTextFieldVar2.setText("");
         jTextFieldVar1A.setText("");
         jTextFieldVar2A.setText("");
         jTextFieldArg1.setText("");
         jTextFieldArg2.setText("");
         jTextFieldArg1A.setText("");
         jTextFieldArg2A.setText("");
     }

完成上述步驟后運行程序,在var1和var2右邊的文本框中輸入兩個整數后單擊“交換”按鈕,發現兩個實參變量在調用交換方法swap后仍然保持原值不變,而兩個形參的值則在執行交換操作后確實進行了交換(見圖4.3)。

圖4.3 整數類型實參不受調用方法的影響

如果方法調用所傳遞的參數是引用類型的變量,則將實參的引用值復制給形參的引用變量。此時,相對應的實參和形參鏈接到同一個對象,在方法中改變了形參引用對象時,其實就是改變了實參引用的對象。

例4.2 TwoInt類中有兩個int類型的屬性,編寫方法swap交換該類對象的兩個屬性的值,并顯示交換前后形參引用對象和實參引用對象的屬性值。

解:按照以下步驟操作。

(1)右擊book.methoddemos包中VarSwap.java文件名,在快捷菜單中單擊“復制”菜單項。右擊book.methoddemos包名,在快捷菜單中單擊“粘貼”|“重構復制”菜單項,新名稱輸入“ObjSwap”,單擊“重構”按鈕。

(2)將“var 1:”“var2:”“arg 1:”“arg2:”標簽上的文字(text屬性)修改為“var.var1:”“var.var2:”“var.arg1:”“var.arg2:”。

(3)右擊book.methoddemos包名,在快捷菜單中單擊“新建”|“Java類”菜單項,類名輸入“TwoInt”,單擊“完成”按鈕。

(4)在TwoInt類中添加兩個整型域,完成后該類的源代碼如下(空行和注釋部分省略)。

     package book.methoddemos;
     public class TwoInt {
         int var1;
         int var2;
     }

(5)修改ObjSwap類中的swap方法。完成修改后該方法的源代碼如下。

     void swap(TwoInt arg) {
         // 顯示交換前形參的值
         jTextFieldArg1.setText(arg.var1+"");
         jTextFieldArg2.setText(arg.var2+"");
         // 執行交換
         int t = arg.var1;
         arg.var1 = arg.var2;
         arg.var2 = t ;
         // 顯示交換后形參的值
         jTextFieldArg1A.setText(arg.var1+"");
         jTextFieldArg2A.setText(arg.var2+"");
     }

(6)修改ObjSwap類中的swapVars方法。完成修改后該方法的源代碼如下。

完成上述步驟后運行ObjSwap.java文件,在var.var1和var.var2右邊的文本框中輸入兩個整數后單擊“交換”按鈕,發現實參變量所引用的對象在調用交換方法swap后發生改變——對象的兩個屬性值發生了交換,形參所引用的對象在執行交換操作后兩個屬性值也進行了交換(見圖4.4)。

圖4.4 例4.2程序運行結果——參數引用的對象發生改變

如果例4.1中的swap方法修改為swap(javax.swing.JTextField arg1, javax.swing.JTextField arg2),在事件處理方法swapVars中調用swap(jTextFieldVar1, jTextFieldVar2),即傳遞接收用戶輸入的兩個文本字段組件的引用,則arg1也鏈接到第一個文本字段組件,arg2鏈接到第二個文本字段組件。在swap方法體內交換arg1和arg2的值,那么只是arg1鏈接到第二個文本字段組件,arg2鏈接到第一個文本字段組件,實參變量jTextFieldVar1仍然鏈接到第一個文本字段組件,jTextFieldVar2仍然鏈接到第二個文本字段組件。顯然,在被調方法中無法改變調用者實參引用。要在被調方法中改變實參引用對象的狀態,可以將該對象引用傳遞給形參,使形參也鏈接到這個對象,之后就可以通過形參引用修改該對象的狀態。

4.1.3 方法的重載

在例4.1和例4.2中看到了兩個同名方法swap,其作用都是交換兩個變量的值,但是由于是在兩個不同的類中,有不同的作用范圍,因此方法名字相同并沒有什么不妥。有時候會遇到在同一個類中作用相同的兩個或多個方法的情形,如果它們也可以使用相同的方法名,則可以減輕該類的使用者的記憶負擔。例如,需要設計方法實施兩個數相加,但是這兩個數可能是整數,也可能是浮點數,甚至是兩個byte類型數;又如,還需要設計方法實施兩個數、三個數、四個數相加。為此,Java語言提供了方法重載機制,可以定義多個具有相同方法名但參數表不同的方法——可以是參數個數相同但類型不同,也可以是參數個數不同。重載的方法應該有相同的返回值類型。

1. 參數個數相同類型不同的重載方法

例如,String類中以下valueOf方法分別使用不同類型的一個參數,而形成方法重載。

public static String valueOf(boolean b):返回boolean參數的字符串表示形式。

public static String valueOf(char c):返回char參數的字符串表示形式。

public static String valueOf(int i):返回int參數的字符串表示形式。

public static String valueOf(long l):返回long參數的字符串表示形式。

public static String valueOf(float f):返回float參數的字符串表示形式。

public static String valueOf(double d):返回double參數的字符串表示形式。

又如,String類中以下兩個indexOf方法參數個數相同,但第一個參數類型不同,而第二個參數類型相同,從而形成方法重載。

indexOf(int ch, int fromIndex):返回在該字符串中指定字符ch第一次出現處的索引,從指定的索引fromIndex開始搜索。

indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出現處的索引,從指定的索引開始。

再如,以下OverloadDemo1類中的三個addNums方法都有兩個參數,但參數類型不同從而形成重載。

2. 參數個數不同的重載方法

例如,String類中以下substring方法是參數個數不同的兩個重載方法。

public String substring(int beginIndex)返回一個新的字符串,它是此字符串的一個子字符串。該子字符串從指定索引beginIndex處的字符開始,直到此字符串末尾。

public String substring(int beginIndex, int endIndex)返回一個新字符串,它是此字符串的一個子字符串。該子字符串是從指定的beginIndex處開始,直到索引endIndex ? 1處的字符序列。因此,該子字符串的長度為endIndex?beginIndex。

再如,在OverloadDemo1類中設計以下兩個方法可以查找計算2~n和m~n自然數中的素數。其中,第一個方法只需給出結束的那個自然數,而第二個方法則需要給出起始和結束的兩個自然數,由于方法參數個數不同而方法名相同構成重載。

4.1.4 構造方法

類的對象中包含域變量,創建了對象就需要對它的域變量進行初始化,盡管沒有明確初始化的域變量會有默認初值,但是大部分情況下默認初值是不能滿足需求的。Java語言允許且鼓勵為類定義構造方法以實現對類對象的初始化。

構造方法與一般方法的結構一樣,但構造方法名與類名相同,不能有返回值,也無返回值類型聲明,參數表可以為空或定義多個參數。根據需要可以為一個類定義多個重載的構造方法。在創建類的對象時自動調用它的構造方法,跟在new操作符之后的就是相應構造方法的調用形式——給出對應的實參表。

例4.3 為例2.7完成的用戶登錄程序界面(見圖2.58)編寫用戶信息類,其中,用戶信息包括用戶名、密碼和用戶身份三個方面的內容。

解:按照以下步驟操作。

(1)右擊book.methoddemos包名,在快捷菜單中單擊“新建”|“Java類”菜單項,類名輸入“User”,單擊“完成”按鈕。

(2)在生成的User類體中添加三個域變量,輸入以下代碼。

     String name;
     String password;
     int job;

(3)單擊主菜單中的“源”|“插入代碼”|“構造函數”菜單項,在“生成構造函數”對話框中單擊“全選”按鈕,然后單擊“生成”按鈕(見圖4.5)。

(4)在“源”代碼編輯窗口右擊,在快捷菜單中單擊“插入代碼”|“getter和setter”菜單項,在“生成getter和setter”對話框中單擊“全選”按鈕,單擊“封裝字段”前面的復選框選取該項,然后單擊“生成”按鈕(見圖4.6)。

圖4.5 “生成構造函數”對話框

圖4.6 “生成getter和setter”對話框

(5)在“源”代碼編輯窗口右擊,在快捷菜單中單擊“插入代碼”|“equals ()和hashCode()”菜單項,在“生成equals ()和hashCode()”對話框中單擊兩個“全選”按鈕,然后單擊“生成”按鈕(見圖4.7)。

圖4.7 “生成equals ()和hashCode()”對話框

(6)單擊主菜單中的“源”|“插入代碼”|“構造函數”菜單項,在“生成構造函數”對話框中單擊name : String前面的復選框選擇該項,然后單擊“生成”按鈕。

完成上述操作步驟后即生成了User類的代碼。該類的源代碼如程序清單4.1所示(省略空行和注釋),可以看到有兩個重載的構造方法。

程序清單4.1:

主站蜘蛛池模板: 抚顺县| 景泰县| 诸暨市| 砚山县| 洱源县| 巫溪县| 揭阳市| 襄樊市| 乐昌市| 襄城县| 洞头县| 和顺县| 青冈县| 酒泉市| 英德市| 南安市| 屏东县| 德江县| 灌南县| 张掖市| 辉南县| 九龙县| 杭州市| 保靖县| 来凤县| 彩票| 湖南省| 宾川县| 拉萨市| 门头沟区| 大田县| 长寿区| 赤城县| 芜湖市| 临清市| 连江县| 万年县| 从江县| 万州区| 邢台市| 海盐县|