使用泛型收集日期

collection of date using generics

我正在阅读 Effective Java 第 23 项中关于泛型的内容。如下所述:

While the prospect of accidentally inserting a coin into a stamp collection may appear far-fetched, the problem is real. For example, it is easy to imagine someone putting a java.util.Date instance into a collection that is supposed to contain only java.sql.Date instances.

我无法理解作者所说的 "it is easy to imagine someone putting a java.util.Date instance into a collection that is supposed to contain only java.sql.Date instances" 是什么意思?

Collection<java.util.Date> dateColl = new ArrayList();
String strDate = "2011-12-31 00:00:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
java.util.Date date = sdf.parse(strDate);
java.sql.Date sqlDate = new Date(date.getTime());

dateColl.add(sqlDate);

为什么上面的代码没有抛出编译错误?

Why above code is not throwing compilation error?

您的集合 dateColl 属于 java.util.Date 类型,因此您可以添加属于 java.util.Date 或其子类型的任何对象,如下所示:

Collection<java.util.Date> dateColl = new ArrayList();
String strDate = "2011-12-31 00:00:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
java.util.Date date = sdf.parse(strDate);
java.sql.Date sqlDate = new Date(date.getTime());
dateColl.add(date); //VALID
dateColl.add(sqlDate);//VALID

事实上,您可以添加 java.sql.Date 对象,如上所示(因为 java.sql.Date extends (IS-A) java.util.Date

date 属于 java.util.Date 类型,这与您为 Collection 声明的类型相同,因此没有错误。但是,java.sql.Date 确实扩展了 java.util.Date,因此您应该能够毫无问题地将两个版本存储在 Collection 中。

I am not able to understand what does author mean by "it is easy to imagine someone putting a java.util.Date instance into a collection that is supposed to contain only java.sql.Date instances"?

在你的例子中:

Collection<java.util.Date> dateColl = new ArrayList();
java.util.Date date = sdf.parse(strDate);
...
dateColl.add(date);

你反其道而行之。您声明了 java.util.Date 的集合。此外,您还在 java.util.Date instance 的集合中添加了一个 java.util.Date 实例。您永远不会使用您声明的 java.sql.Date 实例,当然,在 java.util.Date 的集合中添加一个 java.util.Date 实例不需要任何强制转换,也不会质疑类型兼容性。

从 OOP 的角度来看:java.sql.Datejava.util.Date 类型。所以,这是合法的:

Collection<java.util.Date> dateColl = new ArrayList();
dateColl.add(new java.sql.Date(...));

要理解这个问题,你应该声明:

Collection<java.sql.Date> dateColl = new ArrayList();

然后尝试添加一个 java.util.Date 实例。在那里,您将遇到编译问题,因为 "you are putting a java.util.Date instance into a collection that is supposed to contain only java.sql.Date instances".

如果不在集合 类 中使用泛型,编译将不会失败,因此在运行时,如果您希望有一个只包含 java.sql.Date 的集合,您可能会有 ClassCastException实例:

在这里,您将在循环中有一个 ClassCastException,因为您无法将 java.util.Date 实例转换为 java.sql.Date 实例:

Collection mySqlDates = new ArrayList();
mySqlDates.add(new java.sql.Date(...));
mySqlDates.add(new java.util.Date(...));

for (Object object : mySqlDates) {
    java.sql.Date sqlDate = (java.sql.Date) object; 
}