简体   繁体   中英

hashCode and equals with a list property

I have a class with a for-loop within the equals/hashCode :

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);

    }
}

I am used to have this version (version 2) of equals/hashCode, which is shorter and faster:

@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);

}

Can I replace the former equals/hashCode with the version 2 without worrying about correctness?

Are both versions return the same result?

To sum up:

for typcial List implementation we can use version 2 instead of version 1.

One additional question related to this:

Will version 2 be also valid, if the property task is not a List but a Stream ? ( Stream<Task> tasks ).

Version 2 will work just fine, though it will return slightly different hash codes.

It depends on the specific List implementation. Let's look at what Object.equals does:

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

So it checks for a couple of trivial cases, then calls a.equals(b) , which means that it will call the equals method of your list. But if you're using some custom List or just some list that doesn't compare the elements one by one, then the two implementation will be different.

For any sane implementation, equals should iterate over the elements and compare each one using equals . This is what AbstractList does.

Also note that your hash code will probably change between implementations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM