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也会带来一些其他的问题。
我想这种情况是可以避免的,原则就是只比较具有相同类型的两个对象,而不与其父类或子类比较。如果必须比较的话,也应该用相应的方法转化为相同的类,再进行比较。