可变的 Java 对象是否等于自身?[已关闭]

Does a mutable Java object equal itself? [closed]

提问人:Jared 提问时间:12/5/2021 最后编辑:Zoe is on strikeJared 更新时间:12/5/2021 访问量:195

问:


想改进这个问题吗?通过编辑这篇文章来添加详细信息并澄清问题。

1年前关闭。

我在想可变对象,以及它们是如何奇怪的(但非常酷)。

问题:一个可变对象不能等于它自己吗?

这里唯一需要注意的是,显然您必须重写方法,否则默认检查指针相等性,这将(显然)始终得到满足。equals

编辑到问题

好了,我已经彻底把大家搞糊涂了,看看这个程序:

import java.util.Random;

public class EqualsTest {
    private static final Random RANDOM = new Random(System.currentTimeMillis());

    private int value = 0;

    public static void main(String... args) {
        System.out.println("Starting program...");
        final EqualsTest test = new EqualsTest();
        final Thread modify = new Thread(new Runnable() {
            public void run() {
                while (true)
                    test.value = RANDOM.nextInt(Integer.MAX_VALUE);
            }
        });
        final Thread equals = new Thread(new Runnable() {
            public void run() {
                while (true)
                    if (!test.equals(test)) {
                        System.out.println("test didn't equal test");
                    }
            }
        });

        modify.start();
        equals.start();
    }

    @Override
    public boolean equals(Object e) {
        if (!(e instanceof EqualsTest))
            return false;
        final EqualsTest obj = (EqualsTest) e;
        return this.value == obj.value;
    }
}
爪哇岛 螺纹安全 可变

评论

3赞 khelwood 12/5/2021
如果你覆盖,那么显然它会返回你告诉它返回的任何内容。可变与否无关紧要。我不确定你这个问题的目的是什么。equals
0赞 Jared 12/5/2021
@khelwood 你确实错过了重点......“理智”等于方法怎么可能自行返回 false?
1赞 Turing85 12/5/2021
@Jared “我的问题是'谁在乎方法协定',我们被允许这样做吗?那么答案是肯定的(你轻描淡写地举了一个例子,imo),但即使我们是“理智的”,我们仍然很容易违反这个与可变对象的契约。- 100%同意。所记录的协定不能由运行时强制执行,因此它被记录在案。是的:不正确的实现很容易被忽视(直到程序开始表现得很奇怪)。equals(...)equals(...)
1赞 Cody Gray - on strike 12/5/2021
答案不属于问题!不要将答案编辑到问题中。您可以使用新信息更新问题,但不要将答案添加到问题中。请参加参观
1赞 Cody Gray - on strike 12/5/2021
您无法删除已回答的问题。评论会定期删除,尤其是那些过时或没有提供有用信息的评论。我没有理由保留纯粹基于误解的评论。

答:

4赞 Turing85 12/5/2021 #1

Object::equals 的文档明确指出:

...

该方法在非 null 对象引用上实现等价关系:equals

  • 它是自反的:对于任何非空引用值,应返回 。xx.equals(x)true

...

虽然我们可以以违反此合同的方式实施(正如 khelwood 在此评论中提到的),但它会产生后果。例如,集合 CopyOnWriteArraySet 将无法正常工作:equals(...)

import java.util.concurrent.CopyOnWriteArraySet;

class Ideone {
  public static void main(String[] args) {
    final CopyOnWriteArraySet<Foo> foos = new CopyOnWriteArraySet<>();
    final Foo foo = new Foo();
    foos.add(foo);
    System.out.println(foos.size()); // prints "1"
    foos.add(foo);
    System.out.println(foos.size()); // prints "2"
  }
}

class Foo {
  @Override
  public boolean equals(Object o) {
    return false;
  }
}

Ideone demo

(这是我在 betaRide 回答这个问题时使用的代码的变体)


当我们删除 in 的(错误的)实现并使用默认的 -implementation from 时,集合将按预期运行:CopyOnWriteArraySetequals(...)Fooequals(...)Object

class Foo {
}

Ideone demo

评论

0赞 Jared 12/5/2021
你错过了我关于幂等操作的观点。
1赞 Turing85 12/5/2021
你的问题是:“一个可变的对象不能等于它自己吗?我回答了这个问题。此外:您的帖子不包含短语“idem”。
0赞 Jared 12/5/2021
“它是自反的:对于任何非空引用值 x,x.equals(x) 应该返回 true”......这在哪里执行?如果这是真的,那么 equals 方法应该内置同步功能。出于显而易见的(性能)原因,我们可能不希望这样做,但如果使用可变对象和相等是必需的,则需要在其他地方处理(即确保以线程安全的方式访问等)。
0赞 Turing85 12/5/2021
它就在那里执行:在方法的合同中,写在文档中。
1赞 Turing85 12/5/2021
再说一遍:有合同。合同不能(轻易)在技术层面上执行,因此合同是有记录的。我的微不足道的实现和你的实现在同一点打破了契约:反身属性。这两种实现都缺少一个共同的保障措施() - 这将破坏问题的重点。每个允许返回的实现都会导致我上面描述的问题。equals(...)equals(...)equals(...)equals(...)if (this == o) {return true; }equals(...)x.equals(x)false