genaray
genaray

Reputation: 1180

How do we implement equals() and hashcode() for collections?

Describtion

It is recommended to implement equals() and hashcode() for the entities that are detached and reattached frequently. Especially if we are using a set or collections.

Question

I haven't seen any examples for relationships, so how would we implement those methods correctly in the example below? And do we also need a derived set class that overrides the standard set methods?

Child-Parent relation ship 1:n


/**
 * A component which marks a {@link com.artemis.Entity} as a chunk and stores its most valuable information.
 */
@Entity
@Table(name = "chunk")
@Access(value = AccessType.FIELD)
public class Chunk extends HibernateComponent{

    public int x;
    public int y;
    public Date createdOn;

    @OneToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "chunk_identity", joinColumns = @JoinColumn(name = "identity_id"), inverseJoinColumns = @JoinColumn(name = "id"), inverseForeignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
    public Set<Identity> inChunk = new LinkedHashSet<>();

    @Transient
    public Set<ChunkLoader> loadedBy = new LinkedHashSet<>();

    public Chunk() {}
    public Chunk(int x, int y, Date createdOn) {
        this.x = x;
        this.y = y;
        this.createdOn = createdOn;
    }
}

/**
 * Represents a ID of a {@link com.artemis.Entity} which is unique for each entity and mostly the database id
 */
@Entity
@Table(name = "identity")
@Access(AccessType.FIELD)
public class Identity extends Component {

    @Id public long id;
    public String tag;
    public String typeID;

    public Identity() {}
    public Identity(long id, String tag, String typeID) {
        this.id = id;
        this.tag = tag;
        this.typeID = typeID;
    }
}

Upvotes: 0

Views: 424

Answers (3)

Christian Beikov
Christian Beikov

Reputation: 16430

You should always implement equals and hashCode for entities, preferrably based on the primary key or if available, based on a natural key. The only thing you have to keep in mind is, that if you add an entity to a hash set or as key to a hash map, and the equals/hashCode implementations are based on the primary key, you might get into trouble if no primary key is set on the entity that is added. If the primary key is set during flushing, the hash code of that entity would change which breaks hash sets and hash maps as they require the hash code to be stable. To make this work I usually suggest to rebuild the hash sets or hash maps if really needed. I usually use an implementation like this:

@MappedSuperclass
public class LongSequenceEntity implements Serializable {

    private Long id;

    public LongSequenceEntity() {
    }

    public LongSequenceEntity(Long id) {
        this.id = id;
    }

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (getId() == null || !(o instanceof LongSequenceEntity)) {
            return false;
        }
        return getId().equals(((LongSequenceEntity) o).getId());
    }

    @Override
    public int hashCode() {
        return getId() != null ? getId().hashCode() : 0;
    }
}

Upvotes: 1

FilipA
FilipA

Reputation: 612

Just like Louis Wasserman said in a previous post - "You should implement equals and hashCode for objects you write which contain collections"

There is also a way to generate it automatically.

Depending on what IDE you are using it can generate equals() and hashcode() for you.

In Intellij IDE you can right click inside of the code -> Choose option "Generate" and click on "equals() and hashcode()"

You can see more about intellij option there: https://www.jetbrains.com/help/idea/generating-code.html#generate-getters-setters

Upvotes: 1

Louis Wasserman
Louis Wasserman

Reputation: 198211

The objects of your own types that you are putting into collections should have equals and hashCode implemented. That's exactly the time when it's most important to implement equals and hashCode.

You do not need to -- you should not -- implement equals and hashCode for collection objects, even if they contain other objects.

You should implement equals and hashCode for objects you write which contain collections, and in the implementation of those methods, you should use the collection objects' built-in equals and hashCode methods.

Upvotes: 2

Related Questions