2011年6月16日 星期四

Java Inner Class 記事

inner class的作用並不只是隱藏名稱或程式碼
他最大的效果是能有效及完整的達到"多重繼承"-實際上繼承多個non-interface
以下做深入的筆記

inner class的個用途是當建立一個inner class時
inner class可以存取外圍物件的所有元素而無需添加任何飾詞,如下範例:

interface Selector {
  boolean end();
  Object current();
  void next();
}   

public class Sequence {
  private Object[] items;
  private int next = 0;
  public Sequence(int size) { items = new Object[size]; }
  public void add(Object x) {
    if(next < items.length)
      items[next++] = x;
  }
  private class SequenceSelector implements Selector {
    private int i = 0;
    public boolean end() { return i == items.length; }
    public Object current() { return items[i]; }
    public void next() { if(i < items.length) i++; }
  }
  public Selector selector() {
    return new SequenceSelector();
  }   
  public static void main(String[] args) {
    Sequence sequence = new Sequence(10);
    for(int i = 0; i < 10; i++)
      sequence.add(Integer.toString(i));
    Selector selector = sequence.selector();
    while(!selector.end()) {
      System.out.print(selector.current() + " ");
      selector.next();
    }
  }
} /* Output:
0 1 2 3 4 5 6 7 8 9
*/

 範例的inner class的SequenceSelector可以存取其外部的Sequence的類別成員
不論inner class內放置的層次有多深
所有的outer classes的成員,即使是private修飾也都可以被他存取

inner class必須記錄一個reference指向enclosing class(外圍類別)
當取用外部成員時,編譯器會自動用那個隱藏的reference取得
也因為inner class物件產生時必須要關聯至其enclosing class的某個物件
建構inner class物件的同時必須要有enclosing class的物件

inner class可以寫在程式的任意位置
這不是說他們只會在執行那個段落時產生
他們一樣會跟其他class一起被編譯出來,只是在該段落以外無法被使用

假如不需要inner class物件和enclosing class物件之間的連結關係
可以將inner class宣告為static,而這種class被稱為nested class
nested class在生成物件時不需要外圍class的物件,也無法存取外圍class的非靜態物件
一般的inner class不能擁有static data、static fields或nested class,但nested class都可以有

一般而言,interface內不能加入任何程式碼,但nested class卻可以是interface的一部分
任何加到interface的class會自動成為public和static
甚至可以在inner class中時做外圍的interface
如果想寫出讓某interface的不同實作都可以共用的程式碼時可以這麼做,如下:

public interface ClassInInterface {
  void howdy();
  class Test implements ClassInInterface {
    public void howdy() {
      System.out.println("Howdy!");
    }
    public static void main(String[] args) {
      new Test().howdy();
    }
  }
} /* Output:
Howdy!
*/

繼承inner class則必須注意要先建立外圍類別
指向outer class的reference也必須在建構式由我們建立,如下:

class WithInner {
  class Inner {}
}

public class InheritInner extends WithInner.Inner {
  //! InheritInner() {} // Won't compile
  InheritInner(WithInner wi) {
    wi.super();
  }
  public static void main(String[] args) {
    WithInner wi = new WithInner();
    InheritInner ii = new InheritInner(wi);
  }
}

Java Interface 記事

Interface存在的原因有二:
1.能夠向上轉型為多個型別
2.讓客戶端無法產生物件,確保"介面"的設計意義

如果使用的base class不帶任何函式定義式或任何成員變數
應優先選用Interface,其次才考慮abstract class
基本上在確定某些東西會成為base class,優先考量就是使他成為Interface
過度使用Interfaces會帶來額外的複雜度,必須確定有需求再使用

在類別實作多個Interface時
有不同的Interface間採用相同的method命名會導致出錯,應避免此情形

將Interfaces置於某個class中會形成巢狀的Interfaces
巢狀的Interfaces可以為private,意義是實作他的類別在外部不能向上轉型
而巢狀位於另一個Interface內時,那些Interfaces會自動成為public

2011年6月14日 星期二

Java使用多形時可能犯的錯誤

1.覆寫 private method

import static net.mindview.util.Print.*;

public class PrivateOverride{
    private void f(){  print("private f()"); }
    public static void main(String[] args){
        privateOverride po = new Derived();
        po.f();
    }
}

class Derived extends PrivateOverride{
    public void f(){  print("public f()"); }
}
//output:private f()

private method會自動成為final,也會被derived class遮蔽
例子中的Derived的f()是新的method

2.fields及static methods

物件只有一般的method可以是多形
假如base class 與 derived class 有相同的data member
derived class實際上包含了兩個同名的field,其中一個是繼承而來的
只是要呼叫base class的field就必須使用 super.field 的形式來取得
不過在實務上幾乎不會發生,將fields都宣告為private而不直接存取才是避免混淆的方法

static methos是伴隨著物件,而非個別的objects

Java關鍵字-final

final這個關鍵字依照使用的地方不同會有不同的效果及意義
以3個可以使用final的地方來分析:data、method、classes

final data-

告訴編譯器某塊資料是固定不變
但是在用來修飾object reference時須注意
final 會讓reference固定指向一個物件,但該物件的內容卻還是可以更動,array也是相同情況
Java允許產生留白的finals(blank final)
能宣告資料成員為final但不給予初始值,以保持彈性
例如:

public class BlankFinal{
    private final int i = 0;  //Initialized final
    private final int j;         //Blank final
  
    public BlankFianl(){
         j = 1;    //Initialized blank final
    }
    public BlankFianl(int x){
         j = x;    //Initialized blank final

    }
}

編譯器會強迫必須對所有的finals賦值
如果不是在定義處,就得在建構式中以運算式設定其值
此外,Java也允許將引述宣告為final,意指無法在函式中另該引數改指他處
如:  void doSth(final objectA a){...}

final methods-

使用final methods的原因是鎖住這個函式,使繼承者無法進行override
class中所有的private函式自然就會是final
所以將final用在private函式上沒有意義
假使嘗試要override private method,編譯器只會將其視為該class新建立的函式而不會override

final classes-

將class宣告為final表示此class不允許被繼承

2011年6月10日 星期五

Eclipse上安裝Spring IDE套件

Eclipse版本:Eclipse Java EE IDE 3.6.2  Helios

在Eclipse中輸入Spring的updatesite安裝Spring IDE
updatesite:http://springide.org/updatesite
安裝選擇 Core / Spring IDE 、Extensions(Incubation) / Spring IDE、Resources / Spring IDE
以上三項應該就可以了

遇到無法安裝的情形時
可以嘗試先安裝AJDT套件,簡單查一下資料發現這似乎是AOP技術的一種
套件位置:http://www.eclipse.org/ajdt/
挑最新的版本安裝即可

Java基本型別資訊

Java在運作上還是會將基本型別轉換成物件
透過自動封箱(autoboxing)將基本型別轉換成外覆類別
Java在class的data member為基本型別時會給予預設值
但在區域變數則不成立並會引發錯誤
所以在建立基本型別的物件時最好還是給訂初始值

基本型別              大小           外覆類型            預設值

boolean                  -               Boolean              false
char                    16-bit           Character           '\u0000'(null)
byte                      8-bit           Byte                   (byte)0
short                   16-bit           Short                  (short)0
int                       32-bit           Integer                0
long                    64-bit           Long                   0L
float                    32-bit           Float                   0.0f
double                64-bit           Double                0.0d

高精度數值
BigInteger       -  提供的整數支援任意精度,可以很精確的表達任意長度的整數數值
BigDecimal    -  提供任意精度的定點數,在需要精確小數點後計算的場合中適用

高精度的以上兩個類別雖然可以被視為外覆類別,但沒有對應的基本型別
在int或float型別能做到的在這兩個型別也能做到
只是必須以函式叫用方式取代基本型別的運算子,且速度比較慢
屬於以速度換取精度