30 de octubre de 2018

Objetos - método equals vs operador "=="

En esta entrada vamos a construir varios objetos y vamos a comprobar si son iguales o el mismo.

Lo primero es que hay que distinguir qué queremos decir con iguales y qué con el mismo (que son dos cosas distintas):
  • Ser igual (comparación): es verdadero si el contenido relevante es el mismo. Digamos que tengo la clase Persona y esta clase tiene muchos datos personales, sin embargo para decidir si dos personas son la misma sólo me interesa comparar el número de su tarjeta de identidad. Aunque nos parezca raro, si esa es nuestra definición (en nuestro método equals), dos objetos personas con distinto nombre, fecha de nacimiento o color de pelo serían tratadas como iguales si coinciden en ese número.
  • Ser el mismo (identidad): en la vida real es fácil: un objeto sólo es él mismo. Pensemos que en programación trabajamos el valor de un objeto con variables que apuntan a distintos o al mismo objeto. Así pues la comparación se hará entre dos variables y se dira que es verdadero si apuntan al mismo objeto utilizando el operador de igualdad "==".
En definitiva, no es lo mismo coger dos billetes iguales de la cartera que intentar coger el mismo billete dos veces.

No es lo mismo ser igual a otro (equals), que ser él mismo (==)


Como ya hemos adelantado estas preguntas (igual o el mismo) las resolvemos con dos herramientas: el operador de igualdad "==" y el método equals.

Operador de igualdad

El operador de igualdad "==" devuelve true cuando sus dos variables operandos apuntan al mismo objeto.

Método equals

El método equals(Object obj) debe tener una lógica implementada que nos devuelve true sólo si el contenido que hemos definido relevante es el mismo.

Este método no sólo es importante para las llamadas que hagamos nosotros sino que otras clases que usemos en el futuro como colecciones o mapas entre otras, lo van a usar para su funcionamiento con lo que implementarlas correctamente es una parte fundamental para sacarlas rendimiento.



Demostración

Siguiendo con nuestro ejemplo de coches vamos a añadirle un atributo matrícula. El método equals queremos que nos devuelve true cuando la matrícula y el modelo sea el mismo, asumiendo que al coche le puede faltar una rueda o le pueden haber pintado, pero sería el mismo e igual coche. También sería un coche igual cualquier otro coche del mismo modelo al que le pusieramos la misma matrícula (pero ésta ya sería otro coche, no el mismo, sólo igual). El código completo hasta ahora quedaría así:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public class Coche {
    String modelo;
    String color;
    int numeroDeRuedas;
    String matricula;

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    void setMatricula(String matricula) {
        this.matricula = matricula;
    }
    
    public Coche () {
        numeroDeRuedas = 4;
    }
    
    public Coche (String color) {
        this();
        setColor(color); // como ya tengo el setter lo utilizo
    }
    
    public Coche (String color, String modelo) {
        this(color);
        this.modelo = modelo;
    }

    @Override
    public String toString() {
        return "Placa " + matricula + " - " + modelo + " (" + getColor() + "), " + numeroDeRuedas + " ruedas";
    }

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

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Coche other = (Coche) obj;
        if (matricula == null) {
            if (other.matricula != null)
                return false;
        } else if (!matricula.equals(other.matricula))
            return false;
        if (modelo == null) {
            if (other.modelo != null)
                return false;
        } else if (!modelo.equals(other.modelo))
            return false;
        return true;
    }
    
}

Alguno puede sorprenderse al ver la implementación de los métodos equals y hasCode. Ahora no os pido que sepáis implementarlos, pero cuando se implementa uno formalmente implica que hay que implementar ambos (porque están muy unidos). Vamos a usar Eclipse para ayudarnos como de costumbre usando Source > Generate hasCode() and equals().... Simplemente elegimos en el asistente los campos que quiera tener en cuenta para comparar y le damos a Generar.

Vamos a hacer una prueba con dos coches y ver qué resultado nos dan. Este es el método main que usaremos:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
Coche coche1 = new Coche("Seat Ibiza", "Rojo");
coche1.setMatricula("1234 BBB");
Coche coche2 = new Coche("Seat Ibiza", "Rojo");
coche2.setMatricula("1234 BBB");
Coche coche3 = coche1;

// Igualdad
System.out.println("coche1 y coche2 son iguales: " + coche1.equals(coche2));
System.out.println("Pinto coche2 de Negro");
coche2.setColor("Negro");
System.out.println("Los coches siguen siendo iguales: " + coche1.equals(coche2));
System.out.println("Cambio la matrícula a coche2");
coche2.setMatricula("5555 CCC");
System.out.println("Los coches siguen siendo iguales: " + coche1.equals(coche2));

//Identidad
System.out.println("coche1 y coche2 son el mismo: " + (coche1 == coche2));
System.out.println("coche1 y coche3 son el mismo: " + (coche3 == coche1));

La salida es:

coche1 y coche2 son iguales: true
Pinto coche2 de Negro
Los coches siguen siendo iguales: true
Cambio la matrícula a coche2
Los coches siguen siendo iguales: false
coche1 y coche2 con el mismo: false
coche1 y coche3 con el mismo: true

Con esto ya hemos visto que hay campos importantes para decir si dos objetos son iguales y otros que no importan. También hemos visto que dos objetos distintos pueden darnos el resultado de ser iguales si cumplen nuestra definición de igualdad.

Lo que queda claro es que el mismo objeto siempre va a ser igual a sí mismo (pues el contenido relevante así como el resto son el mismo)

Compárteme

Entradas populares