From Gossip@caterpillar

Java Gossip: 沒有泛型之前

考慮您要設計下面的兩個類別(兩個很無聊的類別,但足以說明需求):
  • BooleanFoo.java
public class BooleanFoo {
private Boolean foo;

public void setFoo(Boolean foo) {
this.foo = foo;
}

public Boolean getFoo() {
return foo;
}
}
  • IntegerFoo.java
public class IntegerFoo {
private Integer foo;

public void setFoo(Integer foo) {
this.foo = foo;
}

public Integer getFoo() {
return foo;
}
}

類別定義時邏輯完全一樣,只是當中宣告的成員型態不同,有點小聰明的程式設計人員會將第一個類的內容複製至另一個檔案中,然後用編輯器「取代」功能一次取 代所有的型態名稱(即將Boolean取代為Integer)。

OK!是有些小聰明,但還是不太聰明,如果類別中的邏輯要修改,您要修改兩個檔案,泛型(Generics)的需求就在此產生,當您定義類 別時,發現到好幾個類別的邏輯其實都相同,就只是當中所涉及的型態不一樣時,使用複製、貼上、取代的功能來撰寫程式只是讓您增加不必要的檔案管理困擾,有 沒有辦法只寫一個檔案就好,畢竟它們的邏輯是相同的。

別忘了,Java中所有的類別都擴充自Object,這樣寫會比較好:

  • ObjectFoo.java
public class ObjectFoo {
private Object foo;

public void setFoo(Object foo) {
this.foo = foo;
}

public Object getFoo() {
return foo;
}
}

由於Java中所有定義的類別,都以Object為最上層的父類別,所以用它來實現泛型(Generics)功能是一個不錯的考量,大部份的人都這麼作,您只要撰寫這麼一個類別,然後可以如下的使用它:
ObjectFoo foo1 = new ObjectFoo();
ObjectFoo foo2 = new ObjectFoo();

foo1.setFoo(new Boolean(true));
// 記得轉換介面
Boolean b = (Boolean) foo1.getFoo();

// 記得轉換介面
foo2.setFoo(new Integer(10));
Integer i = (Integer) foo2.getFoo();

看來還不錯,但是由於傳回的是Object,您必須轉換它的介面,問題出在這邊,粗心的程式設計人員往往會忘了要作這個動作,或者是轉換介面時用錯了型態(像是該用Boolean卻用了Integer),例如:
ObjectFoo foo1 = new ObjectFoo();
foo1.setFoo(new Boolean(true));
String s = (String) foo1.getFoo();
 

要命的是,語法上是可以的,所以編譯器檢查不出錯誤,真正的錯誤要在執行時期才會發生,這時惱人的ClassCastException就會出來搞怪,在使用Object設計泛型程式時,程式人員要再細心一些、小心一些。