JDK5.0已經release很久了,但一直沒機會好好學習一下,今天可有機會了。
先來看一段代碼:
public class TestDate {
public static void main(String[] args) {
Date date = new Date();
Object object = new Object();
Timestamp stamp = new Timestamp(date.getTime());
System.out.println("date&stamp:" + date.compareTo(stamp));
System.out.println("stamp&date:" + stamp.compareTo(date));
System.out.println("date&object:" + date.compareTo(object));
}
}
這段代碼看上去很普通,但是如果用1.4和1.5分別編譯就會出現不同的結果。先來說用1.4編譯的情況:首先用1.4編譯,編譯器不會報錯,如果運行的話,前面兩個輸出語句會分別打印“0,0”,而第三個會throw一個ClassCast exception. 因為Date不能與object比較,但是為什么能編譯通過呢?察看JDK源代碼就可以知道了,Date實現了Comparable接口,這個接口中的CompareTo()方法的參數就是Object。所以Date也不得不有一個以Object為參數的CompareTo()方法,但是這個方法是沒有意義的,Date應該與Date比較,所以Date這個Class里面就出現了兩個ComparaTo方法,一個是以Date為參數,另一個是以Object為參數,這是1.4以前,不得不采用的方法。不然Date就沒法實現Comparable接口了。
JDK1.5中Generics的出現解決了這個問題,如果看1.5中Date類的源代碼的話,就會發現它只有一個CompareTo()方法了,那它怎么來實現Comparable接口呢,這就是Generics的功勞了。在Date聲明時,實現Comparable接口是這么寫的:...Comparable...,并且Comparable接口的聲明是這樣的:Comparable。這個T代表Type。它可以是任何Object。Comparable的實現類只要說明T是什么具體類型就可以了。因此,Date就可以只有一個CompareTo()方法,又可以實現Comparable接口了。如果用1.5編譯上面的Code的話,就會發現這段Code是不能編譯通過的,編譯器會提示“Severity Description Resource In Folder Location Creation Time 2 The method compareTo(Date) in the type Date is not applicable for the arguments (Object)”,這就避免了1.4中出現的問題。我想如果使用了1.5以后咱們編寫代碼時,出現ClassCastException的幾率就會很小了,因為編譯器會替你發現這樣的錯誤。
這就是Generics的好處了。
但是還有一點值得考慮,如果我們去掉錯誤的那一行代碼,在1.5中編譯然后運行,會發現還有地方與1.4的不同。第一行輸出語句會打印1,而不是0,這說明1.5認為具有相同時間的timestamp和date是不同的,但1.4認為它們相同。我有看了一下1.5和1.4的源代碼,發現它們CompareTo(Date ...)的實現方法是不一樣的,可能問題就出現在這里。我沒有試著去讀它的代碼,等有時間,一定好好研究一下。
最后,還有一個問題,如果用1.5編譯并運行,會throw一個ClassCastException,而用1.4則不會出現這個問題。我想這是因為timestamp繼承了Date的CompareTo()方法,所以一個timestamp就可以與Date比較了,但是應用了Generics以后這種情況是不允許的,而且代碼也沒有特殊處理,因此就會有Exception了。看來Generics也會帶來一些其他的問題。
我想這種情況是可以避免的,原則就是只比較具有相同類型的兩個對象,而不與其父類或子類比較。如果必須比較的話,也應該用相應的方法轉化為相同的類,再進行比較。