2008年5月12日 星期一

SCJP - 自修重點筆記與心得 (7)

<<1-5-5>>
Enums 的宣告
  • Java 5.0中的 enum (列舉清單)可以對變數的值加以限制,只能從列舉清單中選擇某一個值。使用 enum 可以減少程式內的臭蟲。
  • enum 可以被宣告成它自己的獨立類別,或類別成員,然而它們不能被宣告在函式內!
  • 若 enum 被宣告成獨立類別,則它只能使用 public 和預設的存取等級。
  • enum 宣告後面的分號,是非必須的
  • 每一個 enum 所列舉的項目,事實上都是 enum 的實體,可以在任何 enum 型別上,藉由呼叫 value() 這個函式,一一取出 enum 的值。
  • 宣告的範例如下:
    1. 獨立類別宣告~
      enum ClothesSize {S, M, L}; //可加分號

      class Clothes {
       ClothesSize size;
      }

      public class ClothesTest {
       public static void main(String[] args) {
        Clothes goods = new Clothes();
        goods.size = ClothesSize.M;
       }
      }
    2. 類別成員宣告~
      class Clothes {
       enum ClothesSize {S, M, L} //可不加分號
       ClothesSize size;
      }

      public class ClothesTest {
       public static void main(String[] args) {
        Clothes goods = new Clothes();
        goods.size = Clothes.ClothesSize.M;
       }
      }


宣告 enum 的建構子、函式和變數
  • 事實上,enum 是一種特殊的類別,所以除了可以利用它來列舉常數之外,還可以對它增加建構子、實體變數、函式和一些被稱為常數特定類別本體(constant specific class body)的非常奇怪的東西。
  • 例:
    enum ClothesSize {
     S(32), M(34), L(36);
     //會自動呼叫傳入 int 的建構子

     ClothesSize(int no) {
      this.no = no;
     }

     private int no;
     public int getNo() {
      return no;
     }
    }

    class Clothes {
     ClothesSize size;

     public static void main(String[] args) {
      Clothes goods1 = new Clothes();
      goods1.size = ClothesSize.S;

      Clothes goods2 = new Clothes();
      goods2.size = ClothesSize.M;

      System.out.println(goods1.size.getNo()); //會印出 32
      System.out.println(goods2.size.getNo()); //會印出 34
     }
    }
  • 絕對不可以直接呼叫 enum 的建構子。enum 的建構子是根據定義在常數後面的引數,而被自動呼叫的。
  • 可以定義 enum 建構子接受多個引數,也可以對它進行多載化的動作。
  • enum 可以定義一個非常奇怪的東西,看起來就像匿名內隱類別(anonymous inner class),它被稱為常數特定類別本體(constant specific class body),當希望某個特定的常數,多載化某個 enum 所定義的函式的時候會用到。
  • 例如當大部份 size 的衣服都是印上"?",只有 L-size 的衣服是印上"!",但又不想在取得圖案的函式中加入if/then的程式碼,所以就可以讓 L 這個常數多載 getPic() 這個函式,如下:
    enum ClothesSize {
     S(32),
     M(34),
     L(36) {
      public String getPic() { //多載在 ClothesSize 定義的函式
       return "!";
      }
     };

     ClothesSize(int no) {
      this.no = no;
     }

     private int no;
     public int getNo() {
      return no;
     }
     public String getPic() {
      return "?";
     }
    }


...以上 CHAPTER 1 結束

2008年5月10日 星期六

SCJP - 自修重點筆記與心得 (6)

<<1-5-4>>
變數的宣告
Java 有兩種型態的變數:
  • 基本資料(Primitives):有 8 種,分別為 char、boolean、byte、short、int、long、double 和 float,宣告後型別無法改變。
  • 參考變數(Reference variables):是用來指涉(refer to,或存取到)到一個物件,一旦宣告成某型別後,就不能更改。一個參考變數可以用來指涉到任何其宣告型別,或宣告類別的子型別(subtype,一個相容的型別)的物件。



基本資料的宣告和範圍
  • 基本資料變數可以被宣告成是類別變數(靜態的)、實體變數、函式參數或區域變數。
  • 可在一行程式碼內同時宣告一個或多個同樣基本型別的基本資料,例:int x, y, z;。
  • 整數型態的基本型別所代表的範圍從小至大順序為:byte, short, int, long。
  • 浮點數的型態則是 double 比 float 大。
  • 數字型態都是帶有正負號的(signed),最左邊的位元(最大有效位元,the most significant digit)被用來表示正負號,1 是負號,0 是正號,其它的位元則使用二系補數表示法(two's complement notation)來表示數值。
  • 數字基本資料的範圍,只須記住前三欄即可。
    TypeBitsBytesMin. RangeMax. Range
    byte81-2727-1
    short162-215215-1
    int324-231231-1
    long648-263263-1
    float324n/an/a
    double648n/an/a
  • 多少位元可代表一個 boolean 值,是由虛擬機器決定的。
  • 一個 char 型別的變數是使用 2 Bytes(16 bits)表示,因此可儲存 unicode 字元。其實 char 是一不帶正負號的(unsigned) 16 位元的整數來表示,可存放 216 的值,範圍為 0 至 65535 (216-1)。


宣告參考變數(Reference Variables)
  • 參考變數可以被宣告成靜態變數、實體變數、函式參數或區域變數。
  • 可以在同一行程式碼內,宣告一個或多個同型別的參考變數,例:String s1, s2, s3;。


實體變數(Instance Variables)
  • 實體變數是被定義在類別內,但在任何函式之外,而且只有在一個類別被實體化的時候,才會進行被始化的動作。
  • 實體變數是屬於每個獨一無二的物件的資料欄(fields)。
  • 實體變數(Instance variable)又可稱為資料欄(field)或屬性(property/attribute)。
  • 實體變數必須知道的規則:
    1. 可使用任何四種存取等級(public, private, protected 或預設)。
    2. 可以被標示成 final, transient。
    3. 不可被標示成 abstract, synchronized, strictfp, native。
    4. 另外也不可標示為 static,因為一旦標示為 static,它就變成了類別變數(class variables,或稱靜態變數)了。
  • 區域變數、實體變數和函式的差異表(可宣告的修飾子):
    區域變數變數(非區域)函式
    finalfinal
    public
    protected
    private
    static
    transient
    volatile
    final
    public
    protected
    private
    static

    abstract
    synchronized
    strictfp
    native


區域(Local,自動 Automatic / 堆疊 Stack / 函式)變數
  • 區域變數就是宣告在函式內部的變數,非該函式的程式碼不可存取該區域變數。
  • 區域變數在函式內部開始它的生命,在函式結束時,區域變數也會被銷毀。
  • 區域變數一定是存在堆疊(stack)內,而不是在堆積(heap)內。
  • 假如該區域變數是一個物件參考,則區域變數還是存於堆疊,而這個物件就會在堆積內被建立出來。所以並沒有存在一個叫做堆疊物件(stack object)的東西,只有堆疊變數。
  • 所謂的區域物件(local object),指的是區域宣告的參考變數(local declared reference variable)。
  • 區域變數只可使用 final 修飾子。
  • 使用區域變數之前,必須先用一個值來初始化它,因為區域變數沒有預設值(實體變數有預設值)。
  • 區域變數的名稱,可以與實體變數相同,這個方法稱為遮蔽(shadowing)。當發生此情形時,該函式要存取同名稱的實體變數時,要加上 this 關鍵字,例:
    class Foo {
    int size = 27;
    public void setSize(int size) {
    this.size = size;
    }
    }


陣列宣告
  • 在 Java 中,陣列是一個物件它可以儲存數個同型別的變數,或同型別的子類別們的變數。
  • 陣列可以被用來儲存基本資料或是物件參考,但即使這個陣列是被宣告來儲存基本資料,陣列本身永遠是堆積裡的一個物件。
  • 建立一個陣列的參考變數:
    1. 宣告一個基本資料的陣列
      int[] key; //建議方式
      int key []; //合法但可讀性較低
    2. 宣告一個物件參考的陣列
      Thread[] threads; //建議方式
      Thread threads []; //合法但可讀性較低
  • 也可宣告多維陣列(multidimensional arrays),其實它就是陣列的陣列,例:
    String[][][] occupantName;//三維陣列宣告
    String[] ManagerName []; //合法的二維陣列宣告,但寫法不好
  • 在宣告陣列時同時宣告陣列的大小是不合法的,例:
    int[5] scores; //此程式碼無法編譯


Final 變數
  • 如果使用 final 這個關鍵字來宣告一個變數,一旦該變數已經被特定的值初始化了(而不是預設的),就不能再次初始化它。
  • 對於基本資料,只要讓變數被指派了一個值,就不能再被改變。
  • 對於物件參考變數(object reference variable),就是不能重新指派它去指涉到另外一個物件,不過讓物件的資料可以被修改,不能被變更的是參考變數。
  • 沒有 final 物件,只有 final 參考。
  • final 的應用意義:
  • 物件(class)final 類別不可被繼承
    函式(method)final 函式不可被子類別覆寫
    變數(variable)final 變數,一旦初始化後,就不能再指派新值


Transient 變數
  • 假如將某類別的實體變數標示成 transient,就是告訴 JVM 在序列化(serialize)包含它的物件的時候,就要忽略它。
  • 序列化是讓你可以儲存(有時候稱為”平坦化(flattern)”)物件的狀態(換句話說,該物件的實體變數的值)到一個 I/O 資料流(stream)上。使用序列化,可以將物件儲存到檔案上,或讓它在網路上傳送,並在另外一端的 JVM 上回復成原物件(再膨脹化(reinflating),反序列化(deserializing))。


Volatile 變數
  • volatile 修飾子告訴 JVM,當一個執行緒存取了該變數,必須將執行緒本身對於該變數的私自拷貝版和記憶體內的主要拷貝版進行一致化的動作。
  • volatile 就像 transient,是一個只可以應用在實體變數的修飾子。


Static 變數和函式
  • 如果類別內的某些函式或變數,和該類別的任何實體是無關的,就可以應用 static 修飾子來建立這些函式或變數。
  • 在建立任何該類別的實體之前,static 成員就已經存在了,而且不論類別有少個實體,這些 static 成員都只有一份,也就是所有實體共享同一份 static 成員。
  • 被標示成 static 的東西有:『函式』、『變數』、『一個包含在另一個類別內的類別(巢狀類別,nested),但不是在函式內的』和『初始化區塊(Initialization blocks)』。
  • 不可被標示成 static 的東西有:『建構子』、『類別』、『介面』、『函式內的區域內隱類別(method local inner classes)』、『內隱類別的函式和實體變數』和『區域變數』。

2008年5月7日 星期三

SCJP - 自修重點筆記與心得 (5)

  這幾天比較忙,所以都沒有時間看我的Java,今天又開始看了一下,以下是今日看的筆記。


<<1-5-2>>
帶有變動個數引數(Variable Argument Lists,簡稱 var-args)的函式
  • 引數與參數的用法~
    引數(arguments):當呼叫函式時,放於括號內的東西,例:doStuff("a", 2);,"a"和2即是引數。
    參數(parameters):放在函式的標記式(method's signature),用來說明這個函式呼叫時所須接收怎樣的資料,例:void doStuff(String s, int a) {},此函數預期有兩個參數,String 和 int。
  • var-args的宣告規則:
    1. var-arg 型別:可以為基本型別(primitive type)或物件型別(object type)。
    2. 基本語法:先是型別,接著是省略符號(...),加一個空白,再接著接收這參數的陣列名稱。
    3. 其他參數:使用 var-arg 的函式可以同時擁有其它參數。
    4. var-arg 的限制:var-arg 必須是函式的標記式上最後一個參數,且一個函式只能有一個 var-arg。
      例:void doStuff(char a, String... b) {}


<<1-5-3>>
建構子 (Constructor) 的宣告
  • 建構子一定不行有回傳型別!
  • 可以使用所有普通的存取修飾子,和擁有引數(包含 var-arg)。
  • 建構子的名稱一定要和類別的名子相同。
  • 建構子不可被標示為 static、final 或 abstract。

2008年4月30日 星期三

SCJP - 自修重點筆記與心得 (4)

<<1-5-2>>
非存取的成員修飾子(Nonaccess Member Modifiers)
  • 包含 final、abstract、transient、synchronized、native、strictfp、static。


Final 函式
  • final 關鍵字可以防止函式被子類別覆寫,而且通常被用來當成 API 的一部份。
  • 防止子類別覆寫函式也扼殺了許多 OO 的優勢,包含透過多型達到可擴充性。


Final 引數(Final Arguments)
  • 在函式宣告的括號中出現的變數宣告,就是函式引數(method arguments),函數引數基本上和區域變數一樣,所以可使用 final,例:
    public Record getRecord(int fileName, final int recordNumber) { ... }
    代表 recordNumber 變數在此函式內,不能被修改。


抽象函式(Abstract Methods)
  • 一個 abstract 函式是指該函式已經被宣告了,但還沒被實作,也就是它沒有函式的主體(method body)。
  • 在一個沒有宣告成 abstract 的類別放進一個抽象函式,是不合法的!可是一個抽象類別可不包含任何抽象函式。
  • 第一個抽象類別的具象子類別(concrete subclass)必須實作所有父類別的抽象函式。
    總覺得這段原文敘述有點怪,還是改為以下:
    當一具象類別(concrete subclass)繼承了抽象類別時,此具象類別必須實作所有父類別的抽象函式。
  • abstract 不可和 final、private 和 static 一起使用。
  • public abstract class A {
     abstract void foo();
    }
    class B extends A {
     void foo(int I) { }
    }
    這段程式碼是無法完成編譯的,因為 B 並未實作 A 的 foo() 抽象函式,而 foo(int I) 只是一個多載化函式(overloaded method,一個使用相同的識別字,但不相同的引數的函式)。
Synchronized 函式
  • synchronized 這個關鍵字是指讓函式一次只能被一個執行緒(thread)存取。

Native 函式
  • native 修飾子是指該函式被和平台相關(platform-dependent)的程式碼實作,通常是 C。
  • 只能用於函式,不可用於類別或變數。
  • 必須注意 native 函式的宣告必須以分號來結尾(就像抽象函式),也就是實作是省略的。
Strictfp 函式
  • strictfp 強迫浮點數(和其他浮點數運算)遵循 IEEE 754 的標準。
  • 優點是可確保每個平台所得到的結果是一致的,且可預測。
    缺點是如困底層的平台支援更精準的浮點數運算,則 strictfp 函式將沒辦法使用到此優點。
  • strictfp 可使用於類別及函式,但不可用於變數。

2008年4月29日 星期二

SCJP - 自修重點筆記與心得 (3)

  今天差點被 protected 存取控制的文章給逼瘋了,算了,還是自己寫程式測一下吧。結果,好險我有測,否則我已經會錯意了!而且還測了書中沒寫到的狀況,跟我預期的一樣,我將它表列如下:



可見性publicprivatedefaultprotected
同一個類別YesYesYesYes
同一個套件內的任何類別YesNoYesYes
同一個套件內的子類別YesNoYesYes
不同套件的任何非子類別YesNoNoNo
不同套件的子類別YesNoNoYes
不同套件的子孫類別YesNoNoYes
與父不同套件但與子同套件的類別,透過子類別的參考,存取父類別YesNoNoNo
與父同套件但與子不同套件的類別,透過子類別的參考,存取父類別YesNoNoYes


區域變數(Local Variables)和存取修飾子(Access Modifiers)
  • 存取修飾子不可應用在區域變數上。
  • 只有 final 修飾子可應用於區域變數。

2008年4月28日 星期一

SCJP - 自修重點筆記與心得 (2)

  哇!今天看的內容讓我的頭很痛,痛不是因為看不懂,是筆記很難寫,主要都是在說明存取修飾子(預設、public、protected、private)在什麼情況下可以被別人存取。我想明天要將這些存取規則列一張表,會比較清楚一點。


<<1-3-1>>
原始檔的宣告規則
  • 每個原始檔中只能有一個 public 類別。
  • 註解沒有限制位置。
  • 如困檔案中有一個 public 類別,則此檔名必須與 public 類別名稱相同;若沒 public 類別,則檔名沒有限制。
  • package 必須出現在第一行,且在 import 之前。
  • import 必須存在於 package 與類別宣告之間;若沒有 package 陳述式,則 import 必須在第一行;若沒有 package 與 import,則類別宣告必須在第一行。
  • package 和 import 陳述式的效力,遍及檔案內的所有類別。
  • 一個檔案可以有多個不為 public 的類別。


<<1-3-2>>
類別的宣告和修飾子
  • 類別宣告之前可加上修飾子,如下:
    1. 存取修飾子(access modifiers):預設、public
    2. 非存取修飾子(Non-access modifiers):strictfp、final、abstract

存取修飾子
  • 雖然存取修飾子有三種,但卻有四種存取控制,其中有兩種可用於類別的宣告上。
    1. public → 均可看到;可用於類別、函式、變數。
    2. private → 只有自己可看見;可用於函式、變數。
    3. protected → 只有同一套件內或子類別可見;可用於函式、變數。
    4. 預設 → 只有同一套件內可見;可用於類別、函式、變數。

非存取類別修飾子
  • strictfp
    1. 只可用於類別及函式。
    2. 類別若標記成 strictfp 的意思是,屬於此類別的所有函式使用浮點數(floating pointes)時,均符合 IEEE 754 標準。
    3. strictfp 也可只宣告於某函式。
    4. 若沒有使用此修飾子,則函式內操作浮點數的方式,就有可能和平台相關,行為就可能不一樣。
  • final
    1. 當類別被宣告為 final,則表示沒有其它類別可再成為它的子類別。例:String。
    2. 身為一個 final 類別,就少了一個 OO 的關鍵優勢~可擴展性(extensibility)。
  • abstract
    1. 不可與 final 合用,因為會產生矛盾。
    2. 一個 abstract 的類別,永遠都不能被實體化(instantiated),它唯一的目的,就是被擴充(繼承,和 final 相反)。
    3. 當類別內只要有一函式被宣告為 abstract,則此類別就必須宣告為 abstract 的類別。

<<1-4-1>>
宣告介面
  • 介面只說明一個類別可以做甚麼,但並不包含說明要如何做。
  • 所有的介面函式都隱含著 public 和 abstract,所以不需要再加此兩種修飾子。
  • 介面只能宣告常數(default 為 public static final),不能是實體變數(instance variables)。
  • 介面函式不可為 static,且函式是抽象的,所以也不能標註 final、strictfp 或 native。
  • 一個介面可以擴充(繼承)一個或多個其他介面,但不可擴充其它非介面的東西。
  • 介面不可實作,且使用 interface 來宣告。
  • 介面型別可以被多型地使用 (can be used polymporphically)。

<<1-4-2>>
宣告介面常數
 介面常數必須宣告為 public static final,但因介面內的變數宣告均為 public static final,所以可以省略,例:int BAR = 42;

<<1-5-1>>
類別成員的宣告
存取修飾子
  • 類別只能使用四種存取等級中的兩種(預設或 public),但成員(members,函式及變數)可以使用全部(預設,public,protected,private)。
  • 存取控制議題可分為兩種:
    1. 一個類別內的函式是否可以存取另一類別的成員。
    2. 一個子類別是否可以繼承它的父類別的成員。

公開成(Public Members)
  • 若成員被宣告為 public,則所有其他類別,不論是否在同一套件內,均可以取此成員。
  • 子類別可完全繼承父類別的所有公開成員,並且可直接使用這些成員,例:父類別有一doThings()函式,子類別可直接呼叫 doThings(),而此成員是暗中透過 this 這個參考來取用,也可寫成 this.doThings(); (this 是指目前正在執行這段程式碼的物件)。

私有成員(Private Memebers)
  • 除了它所屬的類別外,沒有其他類別可以取用。
  • 子類別亦無法繼承父類別的私有成員,當在子類別宣告一個與父類別私有成員一樣名稱的成員是合法的,但這不是覆寫函式

預設成員(Default Members)
  • 只有同一套件內之類別函式可存取,沒有例外。

保護成員(Protected Members)
  • protected 和預設存取控制等級幾乎是相同,但有一關鍵點不同,就是保護成員除了只能讓同套件內的類別存取外,也可以被子類別存取,即使這個子類別在另外一個套件內。而且非一套件的子類別只能透過繼承的方式來看到 protected 成員(不能透過實體操作)。
  • 一但有套件之外的子類別繼承了這個 protected 成員,這個成員對其他的子類別之外的而言,就是 private 的了,但不包含這個子類別的子類別們。(實際測試有一個例外,就是當某一類別與父類別同一套件,與子類別不同套件,可是此類別可以透過子類別的參考存取父類別的 protected 成員)

2008年4月27日 星期日

SCJP - 自修重點筆記與心得 (1)

  第一章都是一些很基本的規則,但是有時也會發現新大陸的感覺,例如識別字可以用$符號,我是第一次聽到,寫那麼久的程式,從來沒有用過。所以,枯燥中也會有一些驚喜!

  不過這個筆記,只是我記錄一些我比較容易忘記細節,並不是全部的課程,所以不一定適合每個人,如果有人跟我一樣想考 SCJP,不應該認為看我的筆記就OK喔!


<<1-2-1>>
合法識別字
  • 識別字須以字母、貨幣符號($)或底線(_)為開頭,不可為數字。
  • 第一個字元之後,可以包含字母、貨幣符號、連結字元(即底線)和數字。
  • 字數沒有上限。
  • 不能使用Java關鍵字。
  • 有區分大小寫。

<<1-2-3>>
JavaBean 屬性命名規則
  • 屬性的型別不是 boolean 時,取值函式的前置字(prefix)必須是get,例:getSize() 為取 "size" 的值,但並不一定需要有 size 這個變數。
  • 屬性的型別是 boolean 時,取值函式的前置字必須為 get 或 is,例:getStopped() 或 isStopped()。
  • 設值函數的前置字必須是 set,例:setSize()。
  • 設值或取值函式必須被標示為 public,格式如下:(屬性名的第一個字要改為大寫)
     設值 >> public void set屬性名(該屬性型別 變數)
         public void setStopped(boolean stopped)
     取值 >> public 該屬性型別 get/is屬性名()
         public boolean getStopped() 或 public boolean isStopped()

JavaBean 的監聽器命名規則
  • 註冊監聽某事件的監聽器函式,必須用前置字 add,再接監聽器的型別,例:addActionListener(),以註冊監聽 Action 事件。
  • 用前置字 remove 來移除註冊監聽某事件,例:removeActionListener()。
  • 用來新增或移除監聽器的型別,必須當引數傳入這個函式。
  • 註冊或移除監聽器的函式,須以"Listener"結尾。