【问题标题】:How to test for equivalence in a generic class?如何测试泛型类中的等价性?
【发布时间】:2013-10-03 18:23:35
【问题描述】:

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.

【问题讨论】:

  • 您可以使用SomeClass.getDeclaredMethod("equals", Object.class) 来检查一个类是否覆盖了Object.equals(Object) 方法。如果一个类确实覆盖了它,那么它很可能会进行某种形式的值比较。但是,仍然不能保证它完全符合您的要求。
  • 您也可以使用相同类型的方法(SomeClass.getDeclaredFields() 然后myField.setAccessible(true)myField.get(myObject) 您还必须使用SomeClass.getSuperclass() 并对所有超类进行相同的比较' fields) 来查找两个对象的字段并递归检查它们是否具有相同的值,但这听起来有点矫枉过正。
  • 欢迎来到 OOP,基本上。
  • @PaulBellora Java,欢迎来到 Java。我们在其他地方有结构等价
  • @PaulBellora Equatable 接口。有些东西确实不应该在结构上进行比较。

标签: java generics scheme equality


【解决方案1】:

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

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

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

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

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

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

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


顺便说一句,你的后记是关于两个裸Objects 的相等性。

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

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


总而言之,假设列表中的所有类型都根据其对象的类型定义了equals()可理解的 版本,Java 的List.equals() 的行为直接类似于Scheme 的equals? 操作。 p>

【讨论】:

    猜你喜欢
    • 2019-10-09
    • 1970-01-01
    • 2018-07-02
    • 1970-01-01
    • 2011-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-11
    相关资源
    最近更新 更多