如何在泛型类中测试等价?

时间:2013-09-27 12:40:25

标签: java generics scheme equality

Scheme知道三种不同的等价运算符:eq?eqv?equal?。有关详细信息,请参阅here。简而言之:eq?测试引用,eqv?测试值,equal?递归测试列表的值。我想编写一个Java泛型,它需要Scheme的equal?

的功能

我尝试使用Java的equals()方法,因为我认为它进行了值比较,因为对于参考比较,==运算符存在且不需要equals做同样的事。但是这个假设是完全错误的,因为Java中的equals完全不可靠。有时它会进行值比较,有时它会进行参考比较。并且不能确定哪个类进行参考比较以及哪个类进行值比较。

这意味着equals不能在通用中使用,因为通用对所有类型都不会这样做。并且也不可能以只接受类型的方式限制泛型类型,以实现正确的值比较。

所以问题是:如何在通用中进行可靠的价值比较?我是否必须自己从头开始写它?

顺便说一句:我认为Java的同等失败不是以Array开头的。它已经开始使用Object。我认为equals两个对象返回false是错误的。它必须返回true,因为如果对某些没有值的值进行值比较,则值不能相同,因此它们必须相同。 Scheme以这种方式完成它并且完全合理:(equal? (vector) (vector)) -> #t

1 个答案:

答案 0 :(得分:0)

在 Scheme 中,列表等价完全基于项目的结构。

相比之下,在 Java 中,相等性取决于对象的类型,并且在其等价性计算中可能会使用部分或全部内部结构。两个相同类型的对象“相等”意味着什么取决于对象类型来确定,只要满足 general contract for equals(最值得注意的是它与所有其他对象形成一个 equivalence relation对象)。

假设程序中使用的所有类型都具有合理的 equals 定义,它们应该具有“可靠”的值比较,至少在面向对象范式的意义上是这样。 >

回到类似的 Java equal? 实现。从问题的措辞中拼凑起来有点困难,但从上下文线索来看,这似乎也试图对项目列表进行操作。 Java 的 equals 类型上的 List 方法已经实现了直接类似于 Scheme 的 equals? 操作的行为:

<块引用>

比较指定的对象与此列表是否相等。返回 true 当且仅当指定的对象也是一个列表,两个列表的大小相同,并且两个列表中所有对应的元素对相等。 (如果 Objects.equals(e1, e2),两个元素 e1 和 e2 相等。)换句话说,如果两个列表以相同的顺序包含相同的元素,则它们被定义为相等。

这个定义也意味着递归列表结构的工作方式与 Scheme 的 equals? 操作类似。

请注意,List 的行为与 Java 的数组类型(您在问题中提到的)的行为明显不同。 Java 中的数组是一种相当低级的类型,不支持人们可能期望的许多典型的面向对象功能。特别要注意的是,对于相等性,数组是通过对象引用而不是通过数组中项目的结构比较来比较的。有一些方法可以使用 Arrays 类中的方法(例如 Arrays.equalsArrays.deepEquals)对数组进行合理的相等比较。


顺便说一句,解决您关于两个裸 Object 相等的后记。

assert !(new Object().equals(new Object()))

从面向对象的角度来看,两个裸对象只有在它们是相同的引用时才相等是明智的。首先,如上所述,对象的内部结构与其相等性之间没有直接关系,因此它们没有需要相等。从对象建模的角度来看,几乎没有关于 Object 的两个不同实例代表什么的上下文,因此没有内在的概念方法来说明这两个对象在逻辑上是“相同”的东西。


总而言之,假设您列表中的所有类型都有一个合理版本的 equals(),根据它们的对象类型定义,Java 的 List.equals() 的行为直接类似于 Scheme 的 {{1 }} 操作。