hashCode 和 equals 列表 属性

hashCode and equals with a list property

我有一个 class,在 equals/hashCode:

中有一个 for 循环
class User {

private List<Task> tasks;
private ZonedDateTime date;


@Override
public int hashCode() {    
    int hash = 17;
    hash = 31 * hash + (date != null ? date() : 0);
    for (var task : tasks) {
        hash = 31 * hash + task.hashCode();
     }

    return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;

        final User other = (User) obj;

        if (tasks.size() != other.tasks.size()) return false;

        // needed?
        for (int i = 0; i < tasks.size(); i++) {
            if (!tasks.get(i).equals(other.tasks.get(i))) {
                return false;
            }
        }

        return Objects.equals(timeStamp, other.timeStamp) && Objects.equals(tasks, other. tasks);

    }
}

我习惯有equals/hashCode的这个版本(版本2),更短更快:

@Override
public int hashCode() {
    return Objects.hash(date, tasks);
}

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null || getClass() != obj.getClass()) return false;

    final User other = (User) obj;
    return Objects.equals(timeStamp, other.timeStamp) && Objects.equals(tasks, other. tasks);

}

我可以用版本 2 替换以前的 equals/hashCode 而不必担心正确性吗?

两个版本return结果相同吗?

总结一下:

对于典型的 List 实现,我们可以使用版本 2 而不是版本 1。

一个与此相关的附加问题:

如果 属性 task 不是 List 而是 Stream 版本 2 是否也有效? (Stream<Task> tasks).

版本 2 可以正常工作,尽管它 return 哈希码略有不同。

这取决于具体的List实现。 让我们看看 Object.equals 做了什么:

public static boolean equals(Object a, Object b) {
    return (a == b) || (a != null && a.equals(b));
}

所以它会检查一些简单的情况,然后调用 a.equals(b),这意味着它将调用列表的 equals 方法。但是,如果您使用的是一些自定义 List 或只是一些不对元素进行一一比较的列表,那么这两个实现将不同。

对于任何合理的实现,equals 应该遍历元素并使用 equals 比较每个元素。这就是 AbstractList 所做的。

另请注意,您的哈希码可能会在不同实现之间发生变化。