2013年9月3日 星期二

The structure of class

作者: 許裕永

從本章開始,各位讀者已經進入另一個層次了。之前我們所寫的程式,雖然也是一個class,但只是單純用來執行,算不上真正開發class。那什麼才是開 發class呢?是開發來讓其他程式中可以使用的class。比如說我們之前在撰寫程式碼時用到的String、Integer、 NumberFormat等等的class。有些可以建構成物件來儲存資料及運算,有些可以呼叫類別成員來協助運算。而這些類別是開發來讓我們在DOS視 窗中,直接用執行指令(java)來執行的嗎?當然不是。
在撰寫class開發程式時,大家要清楚自己的角色,你可以想像自己是上游的程式設計師,開發這個class是為了讓下游的程式設計師使用(當然也是你自己)。也就是要把類別開發者與類別使用者的角色做區隔。
 
1. class宣告
基本語法:[存取限制][類別型態] class ClassName [extends SuperClassName]
存取限制:目前請統一輸入public,細節將於後續章節介紹。
類別型態:請先省略,本章後面節次中介紹。
class:宣告class的關鍵字。
ClassName:自訂的類別名稱,建議用大寫英文字母開頭。
extends:繼承的關鍵字,請先省略,細節將於後續章節介紹。
例一:
public class MyClass{}
請先將此行敍述句撰寫於獨立的java檔,儲存後並編譯。(檔案名稱為:MyClass‧java)
public class UseMyClass{
  public static void main(String[] args){
  MyClass object=new MyClass();
  System.out.println(object);
 }
}
此部份程式碼撰寫於另一個獨立的java檔,儲存後編譯並執行。(檔案名稱為:UseMyClass‧java)
列印結果:MyClass@757aef
把兩個class分開撰寫成獨立的檔案,主要的目的是讓讀者體會類別開發者與類別使用者的角色。當我們撰寫MyClass時,可以假設撰寫UseMyClass並不是你,而是別人在使用你開發的類別MyClass。
 
2. 實體資料成員
類別是物件的設計圖。物件是依照類別中的宣告來建構。物件是一個連續的記憶體區塊,區塊中儲存著這個物件的資料(值)。這些是我們在前面幾章一直強調的觀念。那到底建構物件的記憶體區塊,是依照類別中宣告的什麼東西來配置的呢?是宣告在類別區塊中的變數或參考變數。
如果類別區塊中,只宣告了一個int型別的變數,那麼Java在建構這個類別的物件時,便會配置4個byte的空間。如果類別區塊中,宣告了三個int型 別的變數,那麼Java在建構這個類別的物件時,便會配置12個byte的空間。(實際上不只,但那些記錄Java內部使用資訊的空間,我們不討論)
而這些宣告在類別中的變數,是在類別建構成物件之後,才佔用記憶體空間並儲存資料;而物件被消滅,這些變數自然也被消滅。也就是說:「這些變數是因為物件 的存在而存在,是屬於物件實體的一部份」。所以我們把這些宣告在類別的變數或參考變數稱之為實體資料成員(instance data member)。 意謂著:「記錄實體物件中某一資料的成員」。(有些書說這些變數是物件的屬性attribute,只是說法不同,指的是相同的東西)
 
2-1 宣告及預設值
基本語法:〔存取限制〕[成員型態]資料型別 資料成員名稱;
存取限制:目前請統一輸入public,細節將於後續章節介紹。
資料成員型態:請先省略,本章後面節次中介紹。
例一:
public class MyClass{
 public int a;
 public int b;
}
宣告的語法,和之前宣告變數的差別是:1、宣告的位置,宣告於類別的大括號中的是資料成員,宣告於方法的大括號中的是區域變數。2、存取限制的宣告。3、成員型態的宣告。
有一點要非常注意的是:「資料成員有預設值,而區域變數沒有預設值」。也就是Java在建構物件時,除了配置記憶體之外,也會在配置的記憶體之中,存入該成員宣告型別的預設值。
 
2-2 物件存取實體資料成員
物件可以透過成員存取運算子‘‧’來存取物件成員。
例一:
public class MyClass{
 public int a;
 public int b;
}
public class UseMyClass{
 public static void main(String[] args){
  MyClass object=new MyClass();
  System.out.println(object.a+object.b);
  object.a=10;
  object.b=20;
  System.out.println(object.a+object.b);
 }
}
列印結果:0 30。第一次列印預設值,第二次列印物件指派的值。
 
2-3 命名原則
因為資料成員的存活期比區域變數長,而且被存取的機會也較多,所以應該用比較正式的名稱,例:firstName,studentNumber之類的,不要再用a,b,c了。不過請注意:建議用小寫英文字母開頭(因為大寫代表class)。
 
3. 實體方法成員
物件呼叫宣告於類別中的實體方法成員,這是我們之前常常撰寫的程式敍述句(例:s‧length();)。現在我們要來學會如何開發一個實體方法。
先了解方法(method)是什麼?簡單的說就是:「程式敍述句的集合」。把執行特定運算的程式碼集合在一組大括號中,並給予一個名稱,這就是方法。方法 的最大優點就是可以重複呼叫。在須要用到該特定運算的位置,就寫一行呼叫方法的敍述句,總是比重複撰寫一堆程式碼輕鬆多了。而且除錯也方便,程式碼看起來 也清爽。
類別中,我們把針對實體資料成員,執行特定運算的程式碼,撰寫成一個一個獨立的方法。那麼實體物件,便可以透過這些方法的呼叫,來針對該物件的實體資料成 員,執行特定的運算。所以稱之為實體方法成員(instance method member)。意謂著:「實體物件所能執行的方法」。
 
3-1 方法的宣告語法
基本語法:〔存取限制〕〔方法型態〕運算結果型別 方法名稱(參數列){}
存取限制:目前請統一輸入public,細節將於後續章節介紹。
方法型態:請先省略,本章後面節次中介紹。
運算結果型別:本方法的執行結果是否為一個值(物件)。如果是:「就必須在方法名稱前宣告此值(物件)的型別(類別)」。如果不是:「就必須在方法名稱前面宣告void」。
方法名稱:自訂的方法名稱。
參數列:呼叫本方法時,必須傳遞過來給本方法運算用的值的型別,及其值在本方法中的名稱。(後續節次中有詳細介紹)
例一:
public void abc(){}

public int abc(){}

public String abc(int x){}
 
3-2 物件呼叫實體方法成員
物件可以透過成員存取運算子‘‧’來呼叫方法成員。
例一:
public class MyClass{
 public int a;
 public int b;
 public void show(){
  System.out.println("a=" + a);
  System.out.println("b=" + b);
 }
}
public class UseMyClass{
 public static void main(String[] args){
   MyClass object=new MyClass();
  object.a=10;
  object.b=20;
  object.show();
 }
}
列印結果:a=10 b=20。
 
3-3 中斷方法
如同用break來中斷switch或迴圈一般,方法也可以中斷,其關鍵字為return。
例一:
public class MyClass{
 public int a;
 public int b;
 public void show(){
  if(a==0|| b==0){
   System.out.println("Value Error");
   return;
  }
  System.out.println("a=" + a);
  System.out.println("b=" + b);
 }
}
public class UseMyClass{
 public static void main(String[] args){
  MyClass object=new MyClass();
  object.show();
 }
}
列印結果:Value Error。
當if的條件成立時,執行完Value Error的輸出後,此方法便中斷執行,剩下的兩句輸出便不會執行。在某些狀況下,用這種寫法,可以讓程式碼比較簡潔。如果讀者還記得的話,我們曾經在之前一個身份證字號檢查的範例中,用過這種寫法。
return是返回(回歸)的意思。返回那裏?返回呼叫本方法的敍述句。也就是說:「呼叫敍述句(object‧show())執行時,程式執行權便會轉 移到本方法,來執行本方法的敍述句。當執行到return時,便會把執行權回歸給呼叫本方法的敍述句,繼續執行呼叫本方法的敍述句後面的程式碼」。
若方法中沒有return,便會執行到本方法的最後一行敍述句之後再返回。
 
3-4 運算結果型別的宣告
本方法中的程式碼,運算的目的是什麼?這是在方法設計之前便規劃好的。如果像上一節的範例,並不是為了運算出一個值,而只是某些動作的執行,那麼該方法的 名稱前面便要宣告void。但如果現在設計的方法,是為了運算出(或取得)某一個值(物件),那麼這個方法的名稱前面便要宣告該值(物件)的型別(類 別)。而且運算的結果必須置於return之後。
例一:
public class MyClass{
 public int a;
 public int b;
 public int getA(){
  return a;
 }
 public int getB(){
  return b;
 }
 public int getPlus(){
  return a+b;
 }
}
public class UseMyClass{
 public static void main(String[] args){
  MyClass object=new MyClass();
  object.a=13;
  object.b=25;
  int x=object.getA();
  int y=object.getB();
  int z=x+y;
  if(z==object.getPlus())
   System.out.println(z);
  }
 }

列印結果:38。
在MyClass中我們設計了三個方法,可以分別取得資料成員a,資料成員b及運算a+b的值。因為運算結果為取得一個值(物件),所以要在方法名稱前面 宣告該值(物件)的型別(類別);相對的,方法名稱前面若有宣告運算結果的型別,程式碼中就一定要把運算結果置於return之後。而且該return敍 述一定要有機會執行。
 
例二:
public int test(){
 int a=0;
 if(a==0)
  return;
}
本例會造成編譯錯誤,因為return後面沒有值。
 
例三:
public int test(){
 int a=0;
 if(a==0)
  return 0;
}
特別注意:本例一樣會造成編譯錯誤,因為return敍述置於if之中,不一定會執行。
 
例四:
public int test(){
 int a=0;
 if(a==0)
  return 0;
 else
  return 10;
}
本例正確。
 
例五:
public int test(){
 int a=0;
 if(a==0)
  return 0;
  return 10;
}
本例也正確。
 
例六:
public int test(){
 try{
  return 10;
 }catch(Exception e){}
}
特別注意:本例編譯錯誤。因為try區塊的程式碼不一定會執行。
 
例七:
public int test(){
 try{
  return 10;
 }catch(Exception e){
  return 100;
 }
}
本例正確。
 
例八:
public int test(){
 try{
  return 10;
 }catch(Exception e){}
  return 100;
}
本例也正確。總而言之,程式碼中一定要確保至少有一個“retrun 值”的敍述句能執行。
 
3-5 參數列
在前面的課程中,我們對於參數列的認識是:呼叫方法時,傳遞給方法的值。比方說,要呼叫String物件的charAt(),就必須在小括號中,給一個int型別的值做參數。
現在,站在設計者的角度,參數指的是:本方法運算時會用到的,需要由呼叫敍述提供的值。而呼叫敍述句中所傳遞進來的值,便會置於參數列宣告的參數名稱之中。最後,參數列宣告的參數,屬於本方法的區域變數。
 
例一:
public class MyClass{
 public int a;
 public int b;
 public void setA(int x){
  a=x;
 }
 public void setB(int y){
  b=y;
 }
 public int getA(){
  return a;
 }
 public int getB(){
  return b;
 }
 public int getPlus(){
  try{
   return a+b;
  }catch(Exception e){return a;}
 }
}
public class UseMyClass{
 public static void main(String[] args){
  MyClass object=new MyClass();
  object.setA(33);
  object.setB(44);
  System.out.println(object.getPlus());
 }
}
列印結果:77。
設計了有接受參數的方法,就能接收呼叫敍述句中,所傳遞的值來運算。但是,本例中的兩個有接受參數的方法,所宣告的參數名稱,分別為x及y,是沒有必要的。因為參數是每個方法的區域變數,所以即使兩個參數都命名為x或都命名為y是沒有關係的。
 
3-6 方法成員內部呼叫
類別中的方法,是可以彼此呼叫的。本節將以方法成員內部呼叫的方式,來撰寫範例,讓讀者更深入了解方法開發的細節。
撰寫範例前,請讀者先修改我們之前寫的MyClass(當然你也可以另外寫一個檔案):
public class MyClass{
 public static void main(String[] args){
  MyClass object=new MyClass();
  System.out.println(object);
 }
}
存檔後編譯並執行。(檔案名稱:MyClass‧java)
在前面幾節中,我們把類別的開發及使用分開寫成兩個檔案,是為了讓初學者了解類別開發者及使用者角色上的區隔。當我們真的在開發一個類別的時候,為了測試 方便,我們往往會在類別中寫一個main,然後在main中把自己這個類別做成物件來測試。等到類別開發完成後,再把它刪掉。我們現在正在這麼做。
總而言之,從現在開始,把main當作是另一個class中的程式碼。
例一:
public class MyClass{
 public void callMethod(){
  showMessage("Hello");
 }
 public void showMessage(String str){
  System.out.println(str);
 }
 public static void main(String[] args){
  MyClass object=new MyClass();
  object.callMethod();
 }
}
在callMethod中,以“Hello”為參數,呼叫showMessage()的敍述句,請注意呼叫敍述句前面並沒有“XXX‧”。也就是說:「類別內部中,各個成員的彼此呼叫或存取,都不必透過任何媒介,可以直接呼叫(方法成員)或存取(資料成員)」。
至於main中的程式碼,請記得:「我們是利用這個main來模擬日後使用者使用本類別的情境,所以要把本類別建構成物件後,再用物件呼叫方法」。
本例的執行以使用者的角度而言,只是:「以類別MyClass建構的物件object,呼叫實體方法成員callMethod()」。對使用者來講,他甚至不必知道showMessage()這個方法的存在。
但是以開發者的角度而言:當物件呼叫callMethod()時,它會呼叫showMessage()這個方法,來執行其中的程式碼。
 
例二:
public void callMethod(){
 int a=8;
 showMessage(a);
 System.out.println("callMethod:" + a);
}
public void showMessage(int a){
 a+=2;
 System.out.println("showMessage:" + a);
}
只改變這兩個方法的內容,其他MyClass架構,及main均不變。
列印結果:showMessage:10 callMethod:8。
示範主題:參數是方法的區域變數。在callMethod()中,呼叫showMessage時,以變數a為參數。代表把a變數的值8,複製一份傳遞給 showMessage的參數a。而showMessage的參數a是showMessage這個方法的區域變數,它的a+=2,運算的是它自己的變數 a,和callMethod中的a沒有關係。總之,不同的方法,可以各自擁有名稱相同的區域變數,而參數也算是區域變數。
 
例二:
public void callMethod(){
 int[] array={3,4,5};
 showMessage(array);
 System.out.println("callMethod:" + array[0]);
}
public void showMessage(int[] array){
 array[0]=100;
 System.out.println("showMessage:" + array[0]);
}
列印結果:showMessage:100 callMethod:100。
示範主題:參考變數的指派,是複製參考變數所儲存的物件代號。
相信大家有注意到,showMessage中改變了callMethod中的陣列的值。
在callMethod中以array為參數呼叫showMessage時,就是把array中的值(a101)複製一份傳遞給showMessage的 參數array。結果我們就可以看到,兩個方法中的區域變數,代表同一個物件。所以當我們在showMessage中改變陣列的值時,改變的其實是 callMethod中的陣列。
在其他語法中,把例一和例二的差異稱之為傳值呼叫及傳址呼叫,但是在Java中,並不做這樣的區分。在Java中,參數傳遞的方式只有一種:把變數中的值複製一份,傳遞給參數。只不過若是參考變數,則傳遞的將是物件代號,也就會變成兩個參考變數指向同一個物件。
 
例三:
public void callMethod(){
 String str="Java";
 showMessage(str);
 System.out.println("callMethod:" + str);
}
public void showMessage(String str){
 str="JAVA";
 System.out.println("showMessage:" + str);
}
列印結果:showMessage:JAVA callMethod:Java。
示範主題:String物件的重新指派,便是建構新的String物件。
在callMethod中用參考變數str為參數,呼叫showMessage,就是把str的物件代號複製一份,傳遞給showMessage的參數 str。依照例二的示範,當showMessage改變str的值,不就是改變callMethod中str的值嗎?怎麼回事?
在callMethod中,以str為參數呼叫showMessage時,就是把str中的物件代號,複製一份給showMessage中的參數str。 但是當showMessage執行str=“Java”時,希望大家還記得,在字串的單元中曾經講過,String類別宣告的參考變數可以把字串值置於 ‘=’右側直接指派,這種指派方式,視同建構一個新的String物件。
也就是showMessage中會另外建構一個新的String物件。所以callMethod中的str代表的String物件的值並沒有被改變。
在這裏要鄭重的告訴各位讀者:例三只是為了應付SCJP認證。實務上這樣的程式碼並不常寫,比較常用的是例二的寫法。所以還是要記住:「若是以參考變數當參數,就必須注意物件值有被更改的可能」。
講到認證,再多提醒一點:除了String之外,還有Wrapper Classes中的類別也擁有AutoBoxing的功能哦!自己試試看吧!
 
例四:
public void callMethod(){
 String str=showMessage();
 System.out.println(str);
}
public String showMessage(){
 return null;
}
列印結果:null。
示範主題:宣告類別為本方法運算結果的型別時,可以在return後加上null。代表空值。
 
3-7 Var-args
宣告方法時,在參數列宣告一個參數,就表示此方法被呼叫時,必須接收一個參數;宣告兩個參數就要接收兩個,以此類推。但是如果想要寫一個可以接受任意個參數的方法,要怎麼宣告呢?
例一:
public void callMethod(){
 showMessage(5,8,10,22);
}
public void showMessage(int... a){
 int total=0;
 for(int x:a)
  total+=x;
 System.out.println(total);
}
列印結果:45。
在showMessage的參數列中,宣告的方式是“int‧‧‧ a”,這代表本方法可以接收任意個int型別的參數。而參數a在本方法中是視為陣列。 所以大家也可以看到在範例中是以迴圈來控制變數a。不過要注意的是:「在呼叫此方法時,給的參數是任意個int型別的參數,當然也可以沒有參數甚至可以用 int型別的陣列當參數」。
Variable Argument Lists宣告注意事項:
  • 财 宣告符號“‧‧‧”必須置於宣告型別之後,不是參數名稱之後。
  • 财 宣告的型別可以是基本資料型別,也可以是參考資料型別。
  • 财 參數列中除了Var-args外,也可以宣告其他參數。
  • 财 參數列中只能有一個Var-args樣式的參數。
  • 财 參數列中的Var-args必須置於最後面。
  • 合法宣告:
    void showMessage(int… a){}
    void showMessage(String str,int… a){}
    void showMessage(int a,String… str){}
    不合法宣告:
    void showMessage(int a…){}
    void showMessage(int… a,String… str){}
    void showMessage(int a,String… str){}
     
    3-8 方法的命名原則
    方法的命名原則基本上和資料成員一樣,用小寫英文字母開頭,第二個英文單字再以大寫英文字母開頭串聯。但是有一點要特別強調的是:設計存取資料成員的方法時,一樣依照這個原則命名。
    例一:
    int age;
    String name;
    void setAge(int x){}
    void setName(String str){}
    int getAge(){}
    String getName(){}
    本例的寫法,才符合命名原則,甚至日後寫JavaBean時,是一定要依照這種寫法。請不要為了搭配資料成員的名稱,而把第二個英文單字的開頭寫成小寫字母。
     
    4. 類別成員(static成員)
    屬於類別,可以讓所有本類別建構的物件,共用的成員;而且也可以用類別名稱存取或呼叫的成員,就是類別成員。宣告時只要在宣告句的資料型別前端加上宣告詞static就可以了。
     
    4-1 類別資料成員
    用來儲存可以讓各個物件共同存取的值。如果此值不接受變更,可於於宣告時加上final。
    例一:
    public class MyClass{
     static int count;
     public void showCount(){
      System.out.println("MyClass object count:" + count);
     }
     public static void main(String[] args){
      MyClass.count=0;
      MyClass objectA=new MyClass();
      objectA.count=1;
      MyClass objectB=new MyClass();
      objectB.count++;
      MyClass objectC=new MyClass();
      objectC.count+=1;
      objectC.showCount();
     }
    }
    列印結果:MyClass object count:3。
    示範主題:無論是用類別名稱或本類別建構的任何一個物件,存取的類別成員,都是同一個。
    之前的實體資料成員,是在物件建構時Java才配置記憶體空間,而物件消毀就是那些實體資料成員被消毀。相對的,在程式執行初期,Java會先載入所有本 程式中有使用到的類別。在載入的同時,便會配置記憶體給所有類別的類別資料成員,並給予初值。而且這些成員會存活到程式執行完畢為止。所以無論是,在該類 別還沒有建構任何物件之前,或所有建構的物件都已經被消毀。一樣都可以用類別名稱,來存取類別資料成員。而且在整個程式的執行期間,該類別資料成員所佔用 的記憶體空間並不會改變,所以不管是用類別名稱,或是用物件,存取的都是同一個記憶體空間的值。
     
    例二:
    public class MyClass{
     final static int CLASS_ID=11211;
     public static void main(String[] args){
      System.out.println(MyClass.CLASS_ID);
      MyClass objectA=new MyClass();
      System.out.println(objectA.CLASS_ID);
     }
    }
    列印結果:11211 11211。
    示範主題:1、若類別資料成員的值記錄著共用值,且不希望被變更,可以用final宣告。2、此種類別資料成員的命名,一般均以大寫英文字母搭底線符號。
    這種成員,也就是我們之前曾使用過的類別常數成員(例:Locale‧TAIWAN)。但是在JDK文件中,這種成員都置於Field Summary的表格之中,所以也有人稱之為類別欄位成員。
     
    4-2 類別方法成員
    在方法宣告句的運算結果型別前端,加上static,便是宣告本方法為類別方法成員。類別方法成員可以讓類別名稱呼叫,也可以讓物件呼叫。
    類別方法成員有一個非常重要的注意事項:「方法中不可以存取實體資料成員或呼叫實體方法成員」。因為,類別方法成員可以用類別名稱呼叫。也就是說:「此方法被呼叫時,未必已經建構本類別物件,如何能夠存取或呼叫實體成員?」
     
    例一:
    int a;
    public static void setA(int x){
     a=x;
    }
    本例編譯錯誤。因為變數a不是static,但方法setA()是static。
     
    例二:
    public class Test{
     int a;
     public static void main(String[] args){
      a=0;
     }
    }
    本例編譯錯誤,因為a為實體資料成員,main為static。
     
    例二:
    public class Test{
     int a;
     public static void main(String[] args){
      setA(8);
     }
     public void setA(int x){
      a=x;
     }
    }
    本例編譯錯誤,因為setA()為實體方法成員,main為static。
     
    5. overloading
    我們可以在同一個類別中,開發任意個名稱相同的方法,但是參數列一定要不一樣。這種機制就稱之為Overloading。
    這種機制,方便設計師用同一個名稱,撰寫功能相似,但需要不同參數的方法。例如在JDK文件中,我們可以看到Math的類別裏,max()的方法有三個, 它們提供的功能是一樣的,就是取得兩個參數中的較大值。但是它們可以分別接收不同型別的參數。這就是Overloading。想想看,再加上min()有 四個,如果沒有這個機制,那麼為了比較兩個參數值的大小,就要想7個不同的名稱來命名?昏倒!
     
    5-1 限制與注意事項
    Overloading宣告,沒有什麼要特別注意的事項,不管是在本類別或子類別中都可以使用。只要記得,參數列的個數或參數的位置或參數的型別,任何一個不完全一樣,都是合法的Overloading。而且運算結果的型別也可以不一樣。
    合法的Overloading:
    void valuePlus(){}
    void valuePlus(int a){}
    void valuePlus(float a){}
    void valuePlus(int a,int b){}
    void valuePlus(int a,float b){}
    void valuePlus(float a,int b){}
    int valuePlus(float a,float b){}
    但是呼叫時就要注意,呼叫敍述中的參數值符合那一個方法的參數列。
     
    例一:
    public class MyClass{
     public String valuePlus(int x,int y){
      return "int";
     }
     public String valuePlus(long x,long y){
      return "long";
     }
     public static void main(String[] args){
      MyClass object=new MyClass();
      byte a=9;
      System.out.println(object.valuePlus(a,a));
     }
    }
    列印結果:int。
    示範主題:對於基本資料型態的值,Java會自動轉換參數值來呼叫合適的方法。
     
    例二:
    System.out.println(object.valuePlus(a,(long)a));
    例一中的程式碼只修改這一句,(long)a。
    列印結果:long。
     
    例三:
    public class MyClass{
     public String valuePlus(int x,long y){
      return "int";
     }
     public String valuePlus(long x,int y){
      return "long";
     }
     public static void main(String[] args){
      MyClass object=new MyClass();
      byte a=9;
      System.out.println(object.valuePlus(a,a));
     }
    }
    本例編譯錯誤。特別注意:不是Overloading造成的錯誤。如果把main拿掉,本例編譯是正確的。錯誤是呼叫敍述句引發的,是那一句造成Java大腦打結,不知道到底要呼叫那一個方法。當然這也算是程式設計師的邏輯錯誤。
     
    5-2 AutoBoxing
    AutoBoxing機制在方法呼叫時,無論是參數列,或是運算結果型別,都是適用的。但是如果碰上Overloading就要注意呼叫的對象是誰了。
     
    例一:
    public String valuePlus(int a){
     return "int";
    }
    public static void main(String[] args){
     MyClass object=new MyClass();
     Integer i=8;
     System.out.println(object.valuePlus(i));
    }
    列印結果:int。
    示範主題:如果沒有符合參數型別的方法,Java會自動把Warpper Classes的物件以AutoBoxing或 AutoUnBoxing的方式轉換為適當的參數值,來呼叫方法。
     
    例二:
    public class MyClass{
     public String valuePlus(long a){
      return "long";
     }
     public String valuePlus(Integer a){
      return "Integer";
     }
     public static void main(String[] args){
      MyClass object=new MyClass();
      int i=8;
      System.out.println(object.valuePlus(i));
     }
    }
    列印結果:long。
    示範主題:基本資料型別自動轉換的執行,優先於AutoBoxing。
     
    5-3 Var-args
    當Overloading中使用Var-args時,又是誰優先執行呢?
     
    例一:
    public class MyClass{
     public String valuePlus(int a,int b){
      return "int";
     }
     public String valuePlus(int... a){
      return "Var-args";
     }
     public static void main(String[] args){
      MyClass object=new MyClass();
      int i=8;
      System.out.println(object.valuePlus(i,i));
     }
    }
    列印結果:int。
    示範主題:參數列完全符合的執行,優先於Var-args。
     
    例二:
    將例一main中的int i=8;修改成 byte i=8;,其餘不變。
    列印結果:int。
    示範主題:參數列基本資料型別自動轉換的執行,優先於Var-args。
     
    當Var-args碰上AutoBoxing又是誰優先執行呢?
     
    例三:
    public class MyClass{
     public String valuePlus(Integer a,Integer b){
      return "int";
     }
     public String valuePlus(int... a){
      return "Var-args";
     }
     public static void main(String[] args){
      MyClass object=new MyClass();
      int i=8;
      System.out.println(object.valuePlus(i,i));
     }
    }
    列印結果:int。
    示範主題:AutoBoxing的執行,優先於Var-args。
     
    呼叫敍述句的參數型別,以下列順序呼叫方法:
  • 财 完全一樣
  • 财 自動型別轉換
  • 财 AutoBoxing
  • 财 Var-args
  •  
    6. Constructor
    Constructor翻譯為建構者。意指工程的建設者。但是在程式語言的書中,卻有許多種翻譯。如:建構者、建立者、建構子、建構函式等。作者覺得因為它的寫法,本質上就是一種方法,所以把它叫做建構方法。
    但是建構方法和一般成員方法是有相當差異的:1、它不可以宣告運算結果的型別。因為它運算的結果就一定是建構一個該類別的物件,不可能有其它的運算結果, 自然不必宣告。2、它的名字一定要和類別名稱一模一樣。3、它不是實體方法成員,也不是類別方法成員,程式碼中,建構方法只能用new呼叫。4、建構方法 不被繼承(後續章節介紹)。
    每一個類別要建構成物件,一定要呼叫建構方法。或許讀者還記得前面有些類別是用getInstance()的方法來取得物件。表面上看,是沒有呼叫建構方 法。但事實上,是Java替我們建構了該類別的子類別,並呼叫了子類別的建構方法(後續章節介紹)。總而言之,只要是類別,就一定有建構方法。
    6-1 預設的建構方法
    類別中如果沒有自行撰寫建構方法,編譯器會自動替我們產生一個不需要參數的建構方法。例如我們上一節所撰寫的MyClass中,並沒有撰寫建構方法,還是可以用new呼叫MyClass()。
    6-2 自訂建構方法
    特別注意:若設計師在類別中,撰寫了任何一個建構方法,編譯器將不再提供預設的建構方法。
    例一:
    public class MyClass{
     public MyClass(){
      System.out.println("Create Object.");
     }
     public static void main(String[] args){
      MyClass object=new MyClass();
     }
    }
    列印結果:Create Object‧
    示範主題:自訂無參數的建構方法。
     
    例二:
    public class MyClass{
     public MyClass(String name){
      System.out.println("Create Object:" + name);
     }
     public static void main(String[] args){
      MyClass object=new MyClass("YUNG.");
     }
    }
    列印結果:Create Object:YUNG‧
    示範主題:自訂有參數的建構方法。
     
    例三:
    MyClass object=new MyClass();
    修改main中的敍述句為new MyClass();
    本例編譯錯誤。
    示範主題:類別中自訂任何一個建構方法後,編譯器便不再提供預設的建構方法,而類別中又沒有撰寫不需要參數的建構方法。所以例中new後面的MyClass()呼叫的是沒有參數的建構方法時,就造成編譯錯誤。
     
    6-3 建構方法Overloading
    建構方法可以利用Overloading機制,提供使用者多樣化的參數列變化,來建構該類別物件。
     
    例一:
    public class MyClass{
     public MyClass(){
      System.out.println("Create Object:Guest." );
     }
     public MyClass(String name){
      System.out.println("Create Object:" + name);
     }
     public static void main(String[] args){
      MyClass object=new MyClass();
     }
    }
    列印結果:Create Object:Guest.
    示範主題:多樣化的建構方法,方便使用者建構適當的物件。
     
    7. this
    類別開發時,妥善運算this可以讓程式碼更簡潔。
     
    7-1 this
    特別注意:this不是代表類別,它是代表執行本方法的物件。
     
    例一:
    public class MyClass{
     public MyClass(){
      System.out.println(this);
     }
     public static void main(String[] args){
      MyClass object=new MyClass();
      MyClass object2=new MyClass();
     }
    }
    列印結果:MyClass@35ce36 MyClass@757aef。
    示範主題:this代表執行這個方法的物件。
     
    當然,本例的寫法單純是為了示範this的用法,基本上把this列印出來是不常見的。但是用this當參數卻是以後大家常會用到的技巧,請先記住,this代表執行此方法的物件。
    因為this代表執行方法的物件,所以程式碼中也就可以用“this‧成員”的寫法,來存取或呼叫所有的成員了。
    例一:
    public class MyClass{
     int age;
     public void setValue(int a){
      this.age=a;
     }
     public int getValue(){
      return age;
     }
     public static void main(String[] args){
      MyClass object=new MyClass();
      object.setValue(18);
      System.out.println(object.getValue());
     }
    }
    列印結果:18。
    示範主題:用this存取資料成員。
    如果要存取age這個資料成員,程式碼中直接寫age=a不就好了,幹嘛還用this‧age=a,這不是多此一舉嗎?各位讀者,如果你現在是這樣子想, 小弟本人我真的是為你高興,你想的是對的,這表示本章的內容並沒有讓你大腦打結,也表示你已經向物件導向邁了很大的一步,恭禧!恭禧!
    話說回來,各位未來的偉大的程式設計師們,你開發的類別是要永垂千古的,是必須製作一份類似JDK文件的說明文件,讓人參閱的。問題來了,你參數列的a是 什麼意思?使用者在說明文件中看到a,他怎麼知道要給年齡的值,萬一他給的是身高的值(202),那你的程式不就昏倒了嗎?
    所以方法正確的宣告應該是:setValue(int age),但如此一來如果你方法中的程式碼是:age=age,當然就有問題了。所以this在這個時候就派上用場了:this‧age=age,這表示本物件的age資料成員的值=此方法的區域變數age的值。
     
    例二:
    public class MyClass{
     int age;
     String name;
     public MyClass(int age,String name){
      this.age=age;
      this.name=name;
     }
     public static void main(String[] args){
      MyClass object=new MyClass(18,"YUNG");
      System.out.println(object.name + ":" + object.age);
     }
    }
    列印結果:YUNG:18。
    示範主題:建構方法中使用this。
     
    最常用this來存取成員的,是建構方法。因為類別使用者,在說明文件中,參閱這個建構方法的參數列時,如何讓使用者明瞭每個參數的代表性,是非常重要的,此時this便派上大用場了。
    最後,請特別注意:因為this是代表物件,所以它不能在static的方法之中使用。因為類別方法成員被呼叫時,物件不一定存在。
     
    7-2 this()
    this(參數),只能寫在建構方法中的第一行,用來呼叫本類別的其他建構方法。
     
    例一:
     
    public class MyClass{
        int age;
        String name;
        public MyClass(){
            this(20,"Guest");
        }
        public MyClass(int age,String name){
            this.age=age;
            this.name=name;
        }
        public static void main(String[] args){
            MyClass object=new MyClass();
            System.out.println(object.name + ":" + object.age);
        }
    }
    列印結果:Guest:20。
    示範主題:建構方法呼叫另一個建構方法。
    本例中,使用者呼叫的是沒有參數的建構方法,而沒有參數的建構方法,會以預設的參數值去呼叫另一個有參數的建構方法。這種寫法,在建構方法中需要撰寫大量程式碼的時候,非常好用。設計師可以避免在每個建構方法中,重複撰寫大量的程式碼。
    this()的使用有兩個限制:1、只能在建構方法中使用。2、一定要做為方法中的第一行敍述句。
     
    例二:
    public class MyClass{
     public MyClass(){
      System.out.println("100行程式碼");
     }
     public MyClass(int age,String name){
      this();
      System.out.println("200行程式碼");
     }
     public MyClass(int age,String name,int heigth){
      this();
      System.out.println("50行程式碼");
     }
     public MyClass(int age){
      this(age,"YUNG");
      System.out.println("10行程式碼");
     }
     public static void main(String[] args){
      MyClass object=new MyClass(18);
     }
    }
    列印結果:100行程式碼 200行程式碼 10行程式碼。
    示範主題:妥善運用this(),節省程式碼的撰寫。
    請注意呼叫流程和執行順序是相反的:
    呼叫流程:MyClass(int age)->MyClass(int age,String name)->MyClass()。
    執行順序:MyClass()->MyClass(int age,String name)->MyClass()。
     
    8. final
    final是Java中唯一的一個可以用來宣告所有成員的型態修飾詞。但是意思都差不多,就是終結、最後的意思。
    8-1 final class
    class的宣告句前端加上final表示本類別不可以繼承,意謂著本類別為最終版本,一方面可以維護安全性(避免類別在網路傳遞時被惡意繼承);另一方面也是宣示本類別已達最高境界,不必再修改。
    8-2 final variable
    常數的宣告,適用於實體資料成員,類別資料成員,還有區域變數。要注意的是final的變數和final的參考變數是不一樣的。用final宣告的變數, 只能指派一次,然後儲存於此記憶體空間中的值便不能改變;用final宣告的參考變數,只能建構一次,然後儲存於此參考變數中的“物件代號”便不能改變。 但是,物件的值是可以改的。
    例一:
    import java.util.*;
    import java.text.*;
    public class MyClass{
     final Date d=new Date();
     public MyClass(){
      d.setYear(50);
     }
     public static void main(String[] args){
      MyClass object=new MyClass();
      System.out.println(DateFormat. getDateInstance().format(object.d));
     }
    }
    列印結果:1950年X月X日。
    示範主題:宣告為final的,是參考變數,不是物件。物件值是可以變更的。
    本例中的參考變數在宣告時便已建構物件,然後在建構方法中改變該物件的值,這是合法的。只要參考變數中的物件代號沒有改變,就是合法的。
     
    例二:
    public class MyClass{
     final Date d=new Date();
     public MyClass(){
      d=new Date(50,10,10);
     }
    }
    本例編譯錯誤。因為參考變數d宣告為final,不可以再指派新的物件代號。
    Java中有部份類別的物件,只要把它的參考變數置於‘=’左側,就等同於建構新物件。例:String及Wrapper Classes。但StringBuffer的值是可以變更的哦,不要搞混了。
     
    8-3 final argument
    參數列中的參數也可以宣告為final,其特性和final variable是一樣的。
     
    例一:
    public class MyClass{
     public MyClass(final Date d){
      d=new Date();
     }
     public static void main(String[] args){
      MyClass object=new MyClass(new Date());
     }
    }
    本例編譯錯誤。因為參數d宣告為final就不可以指派新的物件代號。
    以上範例均用參考變數為例,宣告為fianl的一般變數,其值指派後便不能再變更,請自行測試。
     
    8-4 final method
    方法宣告時,在方法型態的位置宣final,表示本方法不接受Overriding。注意,不是Overloading。關於Overriding,本書將在後續章節中介紹。
     
    9. abstract
    abstract抽象的,可以用來宣告類別型態或方法型態,但是不能宣告變數,而且和final是不可並存的。無論是類別或方法,只能宣告final或abstract,不能兩個都宣告。另外類別方法成員(static)也不可以是abstract。
     
    9-1 abstract method
    請注意宣告抽象方法時,因為抽象方法代表尚未定義的方法。所以:方法宣告完畢必須用‘;’結束,不可以加“{}”。
    例一:
    public abstract int getValue();
    方法宣告完,必須用‘;’結束。
    方法宣告時,只有運算結果型別、方法名稱及參數列的位置是固定的,其他宣告修飾詞的位置可以對換。例一也可以寫成:“abstract public int getValue();”。
    抽象方法沒有定義,那它的存在是為什麼呢?它是用來讓子類別繼承後定義的。換個角度來看,就是限定子類別一定要定義這個方法。
     
    9-2 abstract class
    類別型態宣告為abstract,代表為抽象類別。抽象類別不可以建構成物件,也就是不能實體化的意思。注意:即使有撰寫建構方法,也不能建構成物件,但是撰寫建構方法是合法的。
    例一:
    public abstract class MyClass{
        public MyClass(){
        }
    }
    本例編譯成功。
     
    如果抽象不可以建構成物件,那它為什麼存在?為什麼可以有建構方法?抽象類別是為了被繼承,建構方法是為了讓子類別可以指定呼叫。
    關於繼承的話題,本書後續章節中有介紹,現在請先記住兩個規則:
  • 财 抽象類別中,不一定要有抽象方法。
  • 财 擁有抽象方法的類別,一定要宣告為抽象類別。
  • 例一中,沒有抽象方法,但是MyClass是一個合法的抽象類別。表示本類別尚未成熟,必須交由子類別擴充。
    但是如果類別中擁有抽象方法,表示類別中擁有尚未定義的方法,所以本類別當然要宣告為抽象類別,不接受建構成物件。否則萬一物件要呼叫那個尚未定義的方法,不就掛了。
    最後大家應該可以了解,為什麼類別方法成員不可以宣告為abstract呢?因為類別方法成員是一定要定義的,怎麼可能不定義呢?沒有定義的話,萬一使用者用類別名稱呼叫,不就又掛了。
     
    10. 命令列參數
    public static void main(String〔〕 args)寫了那麼久,也到該解析它的時候了。
    public:接受類別外部的呼叫。(下一章介紹)
    static:接受用類別名稱呼叫。
    main:Java Application(DOS視窗)預設呼叫的方法名稱。
    String〔〕 args:將命令列(執行指令)中,置於檔案名稱後方的參數,建構成String物件的陣列後,將該陣列的物件代號指派給參數 args。特別注意:此參數就像之前開發方法時的參數一樣,名稱是可以自訂的,不一定要叫args,因為它是main這個方法中的區域變數。
    為什麼要宣告為static?因為Java在執行這一支程式的時候,並沒有將類別建構成物件,而是以類別名稱呼叫main這個類別方法成員。
    如何傳遞參數?將文字以空白區隔,置於檔案名稱後方,個數沒有限制。
    例一:
    public abstract class MyClass{
     public static void main(String[] args){
      for(String s:args)
      System.out.println(s);
     }
    }
    假設執行指令為:java MyClass Yung 18 man
    列印結果:Yung 18 man。
    示範主題:命令列中置放於類別名稱之後的字串值,會建構成String物件陣列,傳至main方法中的參數args。但是若沒有字串值,也一樣會傳入String物件陣列給args,只不過其陣列長度為0。
     
    11. 初始化區塊
    建構物件時,一定會執行某一個建構方法。所以我們會把建構物件時一定要執行的程式敍述寫在建構方法中。如果建構方法不只一個,有些程式敍述是希望每一個建構方法都能執行的時候,就必須用this(),讓建構方法彼此呼叫,雖然可行,畢竟規劃起來流於繁鎖。
    初始化區塊,不屬於建構方法,但一定會執行,不過有分為實體和類別,執行時機及順序都不一樣。
     
    11-1 實體初始化區塊
    於類別中任意用大括號撰寫的區塊,即為實體初始化區塊。此區塊的程式碼會在建構方法執行之前執行。若有一個以上,會由上往下執行。
    例一:
    public class JavaTest{
        {
            System.out.println("BlockA");
        }
        JavaTest(){
            System.out.println("Constractor");
        }
        {
            System.out.println("BlockB");
        }
        public static void main(String[] args){
            JavaTest jt=new JavaTest();
        }
    }
    列印結果:BlockA BlockB Constractor
    示範主題:初始化區塊依序執行完畢才執行建構方法。
     
    11-2 類別初始化區塊
    於初始化區塊之前加上static,則該區塊為類別初始化區塊。在類別載入(第一次使用)的時候由上而下依序執行。
     
    例一:
    public class JavaTest{
        {
            System.out.println("BlockA");
        }
        JavaTest(){
            System.out.println("Constractor");
        }
        static{
            System.out.println("Static BlockA");
        }
        {
            System.out.println("BlockB");
        }
        static{
            System.out.println("Static BlockB");
        }
        public static void main(String[] args){
            JavaTest jt=new JavaTest();
            JavaTest jt2=new JavaTest();
        }
    }
    列印結果:Static BlockA Static BlockB 
    BlockA BlockB Constractor
    BlockA BlockB Constractor
    示範主題:類別初始化區塊只在類別載入(第一次執行)時依序執行。
     
    12. 認證重點
    12-1 Class宣告
    • 在Java的命名原則中,類別名稱,建議用大寫英文字母開頭。
    12-2實體資料成員
    • 财 宣告在類別中的變數,是在類別建構成物件之後,才佔用記憶體空間並儲存資料;而物件被消滅,這些變數自然也被消滅。也就是說這些變數是因為物件的存在而存 在。是屬於物件這個實體的一部份,所以我們把這些宣告在類別的變數(參考變數)稱之為實體資料成員(instance data member)。
    • 财 資料成員有預設值,而區域變數沒有預設值。
    • 财 資料成員的預設值和陣列元素的預設值是一樣的。
    • 财 物件可以透過成員存取運算子‘‧’來存取物件成員。
    • 财 在Java的命名原則中,資料成員名稱,建議用小寫英文字母開頭。
    12-3 實體方法成員
    •  類別中,我們把針對實體資料成員,執行特定運算的程式碼,撰寫成一個一個獨立的方法。那麼實體物件,便可以透過這些方法的呼叫,來針對 該物件的實體資料成員,執行特定的運算。所以稱之為實體方法成員(instance method member)。意謂著:實體物件所能執行的方法。
    • 财 運算結果型別指的是:方法的執行結果是否為一個值(物件)。如果是:就必須在方法名稱前宣告此值(物件)的型別(類別);如果不是:就必須在方法名稱前面宣告void。
    • 财 參數列指的是:呼叫本方法時,必須傳遞過來給本方法運算用的值的型別,及其值在本方法中的名稱。
    • 财 物件可以透過成員存取運算子‘‧’來呼叫方法成員。
    • 财 如同用break來中斷switch或迴圈一般,方法也可以中斷,其關鍵字為return。
    • 财 方法中沒有return,便會執行到本方法的最後一行敍述句後再返回。
    • 财 如果現在設計的方法,是為了運算出(或取得)某一個值(物件),那麼這個方法的名稱前面便要宣告該值(物件)的型別(類別)。而且運算的結果必須置於return之後;
    • 财 方法名稱前面若有宣告運算結果的型別,程式碼中就一定要把運算結果置於return之後。而且該return敍述一定要有機會執行。
    • 财 參數指的是:本方法運算時會用到的,需要由呼叫敍述提供的值。而呼叫敍述句中所傳遞進來的值,便會置於參數列宣告的參數名稱之中。
    • 财 參數列宣告的參數,屬於本方法的區域變數。
    • 财 類別內部中,各個成員的彼此呼叫或存取,都不必透過任何媒介,可以直接呼叫(方法成員)或存取(資料成員)。
    • 财 在Java中,參數傳遞的方式只有一種:把變數中的值複製一份,傳遞給參數。只不過若是參考變數,則傳遞的將是物件代號,也就會變成兩個參考變數指向同一個物件。
    • 财 若是以參考變數當參數,就必須注意物件值有被更改的可能。
    • 财 String及Wrapper Classes中的類別宣告的參數變數,用‘=’指派新值時,新值是建構新的物件。也是說這些類別建構的物件的值,是不能改變的。
    • 财 宣告類別為本方法運算結果的型別時,可以在return後加上null。代表空值。
    • 财 呼叫Var-args的方法時,給的參數是任意個參數,當然也可以沒有參數甚至可以用陣列當參數。
    • 财 Var-args宣告符號“‧‧‧”必須置於宣告型別之後,不是參數名稱之後。
    • 财 Var-args宣告的型別可以是基本資料型別,也可以是參考資料型別。
    • 财 參數列中除了Var-args外,也可以宣告其他參數。
    • 财 參數列中只能有一個Var-args樣式的參數。
    • 财 參數列中的Var-args必須置於最後面。
    • 财 方法的命名原則基本上和資料成員一樣,用小寫英文字母開頭,第二個英文單字再以大寫英文字母開頭串聯。但是有一點要特別強調的是:設計存取資料成員的方法時,一樣依照這個原則命名。
    12-4 類別成員
    • 财 屬於類別,可以讓所有本類別建構的物件,共用的成員;而且也可以用類別名稱存取或呼叫的成員,就是類別成員。宣告時只要在宣告句的資料型別前端加上宣告詞static就可以了。
    • 财 在程式執行初期,Java會先載入,所有本程式中有使用到的類別。在載入的同時,便會配置記憶體給所有的類別資料成員,並給予初值。
    • 财 無論是,在該類別還沒有建構任何物件之前,或所有建構的物件都已經被消毀,一樣可以用類別名稱,來存取類別資料成員。
    • 财 整個程式的執行期間,該類別資料成員所佔用的記憶體空間並不會改變,所以不管是用類別名稱,或是用物件,存取的都是同一個記憶體空間的值。
    • 财 若類別資料成員的值記錄著共用值,且不希望被變更,可以用final宣告為類別常數成員。而此種類別常數成員的命名,一般均以大寫英文字母搭底線符號。
    • 财 方法宣告句的運算結果型別前端,加上static,便是宣告本方法為類別方法成員。類別方法成員可以讓類別名稱呼叫,也可以讓物件呼叫。
    • 财 類別方法成員有一個非常重要的注意事項:方法中不可以存取實體資料成員或呼叫實體方法成員。
    12-5 Overloading
    • 财 我們可以在同一個類別中,開發任意個名稱相同的方法,但是參數列一定要不一樣。這種機制就稱之為Overloading。
    • 财 參數列的個數或參數的位置或參數的型別,任何一個不完全一樣,都可以是Overloading。而且運算結果的型別也可以不一樣。
    • 财 對於基本資料型態的值,Java會自動轉換參數值來呼叫合適的方法。
    • 财 AutoBoxing機制在方法呼叫時,無論是參數列,或是運算結果型別,都是適用的。
    • 财 如果沒有符合參數型別的方法,Java會自動把Warpper Classes的物件以Auto Boxing或 UnBoxing的方式轉換為適當的參數值,來呼叫方法。
    • 财 基本資料型別自動轉換的執行,優先於AutoBoxing。
    • 财 參數列完全符合的執行,優先於Var-args。
    • 财 參數列基本資料型別自動轉換的執行,優先於Var-args。
    • 财 AutoBoxing的執行,優先於Var-args。
    12-6 Constructor
    • 财 建構方法和一般成員方法是有相當差異的:1、它不可以宣告運算結果的型別。因為它運算的結果就一定是建構一個該類別的物件,不可能有其它的運算結果,自然 不必宣告。2、它的名字一定要和類別名稱一模一樣。3、它不是實體方法成員,也不是類別方法成員,程式碼中,建構方法只能用new呼叫。4、建構方法不被 繼承。
    • 财 類別中如果沒有自行撰寫建構方法,編譯器會自動替我們產生一個不需要參數的建構方法。
    • 财 若設計師在類別中,撰寫了任何一個建構方法,編譯器將不再提供預設的建構方法。
    • 财 建構方法可以利用Overloading機制,提供使用者多樣化的參數列變化,來建構該類別物件。
    12-7 this
    • 财 this不是代表類別,它是代表執行本方法的物件。
    • 财 因為this代表執行方法的物件,所以程式碼中也就可以用“this‧成員”的寫法,來存取或呼叫所有的成員了。
    • 财 因為this是代表物件,所以它不能在static的方法之中使用。
    • 财 this(參數),只能寫在建構方法中的第一行,用來呼叫本類別的其他建構方法。
    12-8 final
    • 财 final是Java中唯一的一個可以用來宣告所有成員的型態修飾詞。
    • 财 class的宣告句前端加上final表示本類別不可以繼承。
    • 财 常數的宣告,適用於實體資料成員,類別資料成員,還有區域變數。
    • 财 用final宣告的參考變數,只能建構一次,然後儲存於此參考變數中的“記憶體位址”便不能改變。但是,物件的值是可以改的。
    • 财 參數列中的參數也可以宣告為final,其特性和final variable是一樣的。
    • 财 方法宣告時,在方法型態的位置宣final,表示本方法不接受Overriding。
    12-9 abstruct
    • 财 abstract抽象的,可以用來宣告類別型態或方法型態,但是不能宣告變數,而且和final是不可並存的。
    • 财 類別方法成員(static)也不可以是abstract。
    • 财 請注意宣告抽象方法時,因為抽象方法代表尚未定義的方法。所以:方法宣告完畢必須用‘;’結束,不可以加“{}”。
    • 财 抽象方法沒有定義,那它的存在是為什麼呢?它是用來讓子類別繼承後定義的。換個角度來看,就是限定子類別一定要定義這個方法。
    • 财 類別型態宣告為abstract者,代表為抽象類別。抽象類別不可以建構成物件,也就是不能實體化的意思。注意:即使有撰寫建構方法,也不能建構成物件,但是撰寫建構方是合法的。
    • 财 抽象類別中不一定要有抽象方法。
    • 财 擁有抽象方法的類別一定要宣告為抽象類別。
    12-10 命令列參數
    • 财 Java Application執行時,會把命令列(執行指令)中,置於檔案名稱後方的參數,建構成String物件的陣列後,將該陣列的物件代號指派 給參數args。特別注意:此參數就像之前開發方法時的參數一樣,名稱是可以自訂的,不一定要叫args,因為它是main這個方法中的區域變數。
    • 财 參數的傳遞是將文字以空白區隔,置於檔案名稱後方,個數沒有限制。
    • 财 命令列中置放於啟動類別名稱之後的字串值,會建構成String物件陣列,傳至main方法中的參數args。但是若沒有字串值,也一樣會傳入String物件陣列給args,只不過其陣列長度為0。
    12-11初始化區塊
    • 财 於類別中任意用大括號撰寫的區塊,即為實體初始化區塊。此區塊的程式碼會在建構方法執行之前執行。若有一個以上,會由上往下執行。
    • 财 類別初始化區塊只在類別載入(第一次執行)時依序執行。

    沒有留言:

    張貼留言

    注意:只有此網誌的成員可以留言。