Equals et Hashcode : Pourquoi et comment les redéfinir

Lorsque l'on veut utiliser des objets, plus précisément des bean entités, dans des collections, il faut redéfinir les méthodes equals() et hashcode(). Il est judicieux de réfléchir à la meilleure façon de les implémenter.


Le bean entité peut être un value object. Si l'on change une de ses valeurs, ce n'est plus le même objet.
public class Address {
    private Integer number;
    private String streetName;
    private Integer zip;
    private String city;
 
    public Address(Integer number, 
                  String streetName, 
                   Integer zip, 
                   String city) {
        this.number = number;
        this.streetName = streetName;
        this.zip = zip;
        this.city = city;
    }
 
    public Integer getNumber() {
        return number;
    }
 
    public String getStreetName() {
        return streetName;
    }
 
    public Integer getZip() {
        return zip;
    }
 
    public String getCity() {
        return city;
    }
}
Dans ce cas, il est normal de redéfinir ces 2 méthodes en se basant sur les 4 attributs du bean.
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
 
    Address address = (Address) o;
 
    if (city != null ? !city.equals(address.city) : address.city != null)
        return false;
    if (number != null ? !number.equals(address.number) : address.number != null) 
        return false;
    if (streetName != null ? !streetName.equals(address.streetName) : address.streetName != null) 
        return false;
    if (zip != null ? !zip.equals(address.zip) : address.zip != null) 
        return false;
 
    return true;
}
 
@Override
public int hashCode() {
    int result = number != null ? number.hashCode() : 0;
    result = 31 * result + (streetName != null ? streetName.hashCode() : 0);
    result = 31 * result + (zip != null ? zip.hashCode() : 0);
    result = 31 * result + (city != null ? city.hashCode() : 0);
}

Prenons le cas maintenant d'un bean entité qui représente un enregistrement de la base. Seul son attribut ID (qui est sa  Primary_Key) le différencie d'un autre objet.
Prennons l'exemple d'un objet person en JPA
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
 
@Entity
public class Person {
    @Id
    @GeneratedValue
    private Long id;
 
    private String firstName;
    private String lastName;
 
    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
 
    public Long getId() {
        return id;
    }

    //getter et setter de firstName et lastName
}
Dans ce cas, on redéfini les méthodes equals et hashcode seulement en considérant le champ ID.
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
 
    Person person = (Person) o;
 
    if (!id.equals(person.id)) return false;
 
    return true;
}
 
@Override
public int hashCode() {
    return id.hashCode();
}

Aucun commentaire:

Enregistrer un commentaire