“一致性相等”的陷阱
作者:网络转载 发布时间:[ 2013/4/10 9:44:01 ] 推荐标签:
Double/Float--该类显式地提供了排序规则,并为正零和负零,以及NaN都提供了相等性检查,以确保它的compareTo()方法符合“一致性相等”。
CharSet--该类基于ID或名称。equals()方法对待字段串是大小写敏感的,但compareTo()方法却不这样。虽然名称一般会符合某种标准,但这是一种值得怀疑的“一致性”。
*Buffer(nio)--该簇类的比较基于缓冲存放的内容,在我的测试中equals()和compareTo()是“一致的”。
Rdn(ldap)--该类的比较基于状态的标准化格式,因此也是“一致性相等”。
ObjectStreamField(序列化)--该类的比较基于名称,但会首先对基本数据类型进行排序。因为没有覆盖equals()方法,所以是“非一致性相等”。
...
注意:对于大多数的例子,我都不得不查看其源代码或编写测试程序以确定该类是不是符合“一致性相等”。这儿有一个不错地清理Javadoc和检验UUID equals()方法的Adopt-a-JDK任务。
JSR-310
一直看到许多关于BigDecimal的问题,已有计划将JSR-310中的类改造成“一致性相等”,近的一些帖子显示这将造成多么大的争议。
基本上,为某些类定义equals()和compareTo()看起来很容易。LocalDate表示某单一日历系统中的某个日期,所以它有一个显而易见的排序算法和相等规则。LocalTime则表示某个时刻,所以它也有一个明显的排序算法和相等规则。Instant表示时间线上的某个时刻,那么它的排序与相等也是显见的。
但在其它的情况下,这不是那么显而易见了。考虑这样一个类OffsetDateTime:
dt1 = OffsetDateTime.parse("2012-11-05T06:00+01:00");
dt2 = OffsetDateTime.parse("2012-11-05T07:00+02:00");
这样的两个日期-时刻对象代表时间线上一个相同的时刻点,但它们有不同的本地时,而且相对的UTC/格林威治时间的偏移量也不相同。
那么有一个问题要留给读者们...你更倾向于如下哪种观点...
1、dt1不等于dt2,compareTo()分别比较本地时与偏移量,使用“一致性相等”(使用独立的Comparator基于时刻对其进行排序)。
2、dt1不等于dt2,compareTo()基于时间线的上时刻点,使用“非一致性相等”。
3、dt1等于dt2,compareTo()基于时间线的上时刻点,使用“一致性相等”。
4、dt1等于dt2,且不实现Comparable接口。
5、dt1不等于dt2,且不实现Comparable接口。
我个人更倾向于让dt1.equals(dt2)返回true这种方案,但我仍持开放态度。
顺便地,也可以将这个问题提给BigDecimal,如果你能修改这个类,使其符合“一致性相等”,你会修改它的equals()方法,还是compareTo()方法?

sales@spasvo.com