如何实现非对称等于函数?

How can I implement asymmetric equals funciton?

在我的 java 程序中,我有一个映射,其中包含 someID 和 MyClass 类型的数据对象之间的相关性。

ConcurrentMap<Integer, MyClass> a;

我不经常但经常检查 "value" 对象之一是否包含某个 long 作为变量 b。由于我不知道将 someId 与我的 otherId 相关联,因此我无法通过地图访问它。 为此,我想使用 containsValue:

a.containsValue(otherId)

为此,我重写了 hashCode 和 equals 函数。

@Override
public boolean equals(Object o) {
    if ((o instanceof MyClass) && (((MyClass) o).someId().equals(this.someId()))) {
        return true;
    } else
    if ((o instanceof Long) && ((Long) o) == this.otherId) {
        return true;
    } else {
        return false;
    }
}

注意:代码中的otherId不一定是地图的someID。

第一个 if 语句是对称的,第二个显然不是。我知道这不好,但每次都写一个循环也不好。 在 this post 他们说不对称的 equals 将被忽略。如何让 java 忽略不对称问题?

简而言之:不要尝试使用 equals() 执行此操作。该方法的契约是它应该是对称的(以及自反、传递和具有一些其他属性)。有关 equals 所需属性的完整描述,请参阅 Javadoc

类 在 Java API(以及更普遍的情况下)被实现为期望此 属性 成立,因此如果您故意违反,可能会出现意外行为合同。

向您的 类 添加一个新方法,该方法明确用于测试此不对称 属性,例如compareAssymetrically.

您的 equals 实施的问题在于,对于 Long 实例 lMyClass 实例 mm.equals(l) 可能 return true 而 l.equals(m) 将始终 return false,因为您无法更改 Longequals 的实现。

如果您使用任何使用 equalsArrayListHashMap 等...)的 类,您无法控制是否 m.equals(l)l.equals(m) 被调用,因此您的代码可能不会按照您希望的方式运行。

如果要检查 Long 是否是 "equal" 到 MyClass 实例,请创建一个 MyClass 实例,其 otherId 等于该实例Long,并比较这两个 MyClass 个实例。

@Override
public boolean equals(Object o) {
    if (o instanceof MyClass) { 
        MyClass m = (MyClass) o;
        if (m.someId().equals(this.someId())) {
            return true;
        } else if (m.otherId == this.otherId) {
            return true;
        } else {
            return false;
        }
    } 
    return false;
}

public boolean equals(Long l) {
    MyClass m = new MyClass();
    m.setOtherId(l);
    return equals(m);
}

如果你用的是Java-8,写起来不是很难:

a.values().stream().anyMatch(myObj -> myObj.otherId() == wantedId);