Do I need to implement hashCode() and equals() methods?

情到浓时终转凉″ 提交于 2019-12-19 09:56:09

问题


If I have a map and an object as map key, are the default hash and equals methods enough?

class EventInfo{

    private String name;
    private Map<String, Integer> info
 }

Then I want to create a map:

Map<EventInfo, String> map = new HashMap<EventInfo, String>();

Do I have to explicitly implement hashCode() and equals()? Thanks.


回答1:


Yes, you do. HashMaps work by computing the hash code of the key and using that as a base point. If the hashCode function isn't overriden (by you), then it will use the memory address, and equals will be the same as ==.

If you're in Eclipse, it'll generate them for you. Click Source menu → Generate hashCode() and equals().

If you don't have Eclipse, here's some that should work. (I generated these in Eclipse, as described above.)

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((info == null) ? 0 : info.hashCode());
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (!(obj instanceof EventInfo)) {
        return false;
    }
    EventInfo other = (EventInfo) obj;
    if (info == null) {
        if (other.info != null) {
            return false;
        }
    } else if (!info.equals(other.info)) {
        return false;
    }
    if (name == null) {
        if (other.name != null) {
            return false;
        }
    } else if (!name.equals(other.name)) {
        return false;
    }
    return true;
}



回答2:


Yes, you need them else you won't be able to compare two EventInfo (and your map won't work).




回答3:


Strictly speaking, no. The default implementations of hashCode() and equals() will produce results that ought to work. See http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#hashCode()

My understanding is that the default implementation of hashCode() works by taking the object's address in memory and converting to integer, and the default implementation of equals() returns true only if the two objects are actually the same object.

In practice, you could (and should) probably improve on both of those implementations. For example, both methods should ignore object members that aren't important. In addition, equals() might want to recursively compare references in the object.

In your particular case, you might define equals() as true if the two objects refer to the same string or the two strings are equal and the two maps are the same or they are equal. I think WChargin gave you pretty good implementations.




回答4:


Depends on what you want to happen. If two different EventInfo instances with the same name and info should result in two different keys, then you don't need to implement equals and hashCode.

So

EventInfo info1 = new EventInfo();
info1.setName("myname");
info1.setInfo(null);
EventInfo info2 = new EventInfo();
info2.setName("myname");
info2.setInfo(null);

info1.equals(info2) would return false and info1.hashCode() would return a different value to info2.hashCode().

Therefore, when you are adding them to your map:

map.put(info1, "test1");
map.put(info2, "test2");

you would have two different entries.

Now, that may be desired behaviour. For example, if your EventInfo is collecting different events, two distinct events with the same data may well want to be desired to be two different entries.

The equals and hashCode contracts is also applicable in a Set.

So for example, if your event info contains mouse clicks, it may well be desired that you would want to end up with:

Set<EventInfo> collectedEvents = new HashSet<EventInfo>();
collectedEvents.add(info1);
collectedEvents.add(info2);

2 collected events instead of just 1...

Hope I'm making sense here...

EDIT:

If however, the above set and map should only contain a single entry, then you could use apache commons EqualsBuilder and HashCodeBuilder to simplify the implementation of equals and hashCode:

@Override
public boolean equals(Object obj) {
    if (obj instanceof EventInfo) {
        EventInfo other = (EventInfo) obj;
        EqualsBuilder builder = new EqualsBuilder();
        builder.append(name, other.name);
        builder.append(info, other.info);
        return builder.isEquals();
    }
    return false;
}

@Override
public int hashCode() {
    HashCodeBuilder builder = new HashCodeBuilder();
    builder.append(name);
    builder.append(info);
    return builder.toHashCode();
}

EDIT2:

It could also be appropriate if two EventInfo instances are considered the same, if they have the same name, for example if the name is some unique identifier (I know it's a bit far fetched with your specific object, but I'm generalising here...)



来源:https://stackoverflow.com/questions/15351261/do-i-need-to-implement-hashcode-and-equals-methods

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!